diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 727145d07fe..ce6b2ea06e9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,21 +11,11 @@ updates: - "auto.dependencies" - "auto.github-action" - "lang.yaml" - - package-ecosystem: "npm" - directory: "/" - schedule: - interval: "daily" - allow: - - dependency-type: "production" - labels: - - "auto.dependencies" - - "auto.npm" - - "lang.javascript" - package-ecosystem: "pub" versioning-strategy: "increase-if-necessary" directories: - "/" - - "/tool/flutter_site" + - "/tool/dash_site" schedule: interval: "daily" labels: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eab7cbfd266..2a30a4b08cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,9 +13,6 @@ on: # Declare default permissions as read only. permissions: read-all -env: - NODE_VERSION: 22 - jobs: test: name: Analyze and test code examples @@ -41,13 +38,13 @@ jobs: run: dart pub get continue-on-error: ${{ matrix.experimental }} - name: Check Dart code formatting - run: dart run flutter_site format-dart --check + run: dart run dash_site format-dart --check continue-on-error: ${{ matrix.experimental }} - name: Analyze Dart code - run: dart run flutter_site analyze-dart + run: dart run dash_site analyze-dart continue-on-error: ${{ matrix.experimental }} - name: Run Dart tests - run: dart run flutter_site test-dart + run: dart run dash_site test-dart continue-on-error: ${{ matrix.experimental }} excerpts: @@ -62,24 +59,15 @@ jobs: - name: Fetch Dart dependencies run: dart pub get - name: Check if excerpts are up to date - run: dart run flutter_site refresh-excerpts --fail-on-update --dry-run + run: dart run dash_site refresh-excerpts --fail-on-update --dry-run continue-on-error: ${{ matrix.experimental }} linkcheck: name: Build site and check links runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 - - name: Enable Corepack - run: npm i -g corepack@latest && corepack enable - - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'pnpm' - - name: Setup pnpm - run: corepack install - - name: Install node dependencies - run: pnpm install --frozen-lockfile - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: sdk: beta @@ -88,11 +76,11 @@ jobs: - name: Install firebase-tools run: curl -sL https://firebase.tools | bash - name: Build site - run: dart run flutter_site build + run: dart run dash_site build - name: Check for broken Markdown link references - run: dart run flutter_site check-link-references + run: dart run dash_site check-link-references - name: Check for broken internal links - run: dart run flutter_site check-links + run: dart run dash_site check-links firebase-validate: name: Validate Firebase configuration @@ -106,4 +94,4 @@ jobs: - name: Fetch Dart dependencies run: dart pub get - name: Validate the firebase.json file - run: dart run flutter_site verify-firebase-json \ No newline at end of file + run: dart run dash_site verify-firebase-json \ No newline at end of file diff --git a/.idx/dev.nix b/.idx/dev.nix index 271ae3a3590..45c6fa715f1 100644 --- a/.idx/dev.nix +++ b/.idx/dev.nix @@ -6,8 +6,8 @@ # Use https://search.nixos.org/packages to find packages packages = [ - pkgs.nodejs_22 - pkgs.pnpm + # Node is included for deploying to Firebase. + pkgs.nodejs_24 ]; # Sets environment variables in the workspace @@ -24,7 +24,7 @@ enable = true; previews = { web = { - command = ["./dash_site" "serve"]; + command = ["dart" "run" "dash_site" "serve"]; manager = "web"; env = { # Environment variables to set for your server @@ -38,12 +38,11 @@ workspace = { # Runs when a workspace is first created onCreate = { - pnpm-install = "pnpm install"; + dart-pub-get = "dart pub get"; }; # Runs when the workspace is (re)started onStart = { - # Example: start a background task to watch and re-build backend code - # watch-backend = "npm run watch-backend"; + dart-pub-get = "dart pub get"; }; }; }; diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index b009dfb9d9f..00000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -lts/* diff --git a/README.md b/README.md index 4d38a94214f..3c02d5a0f50 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ # [Flutter][] documentation website The [documentation site][Flutter] for the [Flutter framework][], -built with [Eleventy][] and hosted on [Firebase][]. +built with [Jaspr][] and hosted on [Firebase][]. [Flutter framework]: https://flutter.dev -[Eleventy]: https://11ty.dev/ +[Jaspr]: https://jaspr.site [Firebase]: https://firebase.google.com/ [Build Status]: https://github.com/flutter/website/workflows/build/badge.svg @@ -88,12 +88,9 @@ enable an edit-refresh cycle. ### Get the prerequisites -Install the following tools to build and develop the site: +To build and develop the site, you'll need to +install the latest stable release of Flutter, which includes Dart. -#### Flutter - -The latest stable release of Flutter, which includes Dart, -is required to build the site and run its tooling. If you don't have Flutter or need to update, follow the instructions at [Install Flutter][] or [Upgrading Flutter][]. @@ -107,28 +104,6 @@ flutter --version [Install Flutter]: https://docs.flutter.dev/get-started [Upgrading Flutter]: https://docs.flutter.dev/release/upgrade -#### Node.js - -The **latest** stable LTS release of Node.js is required to build the site. -If you don't have Node.js or need to update, download your -computer's corresponding version and follow the instructions -from the [Node.js download archive][]. -If you prefer, you can use a version manager such as [nvm][], -and run `nvm install` from the repository's root directory. - -If you already have Node installed, verify it's available on your path -and already the latest stable version _(currently `22.14` or later)_: - -```console -node --version -``` - -If your version is out of date, -follow the update instructions for how you originally installed it. - -[Node.js download archive]: https://nodejs.org/en/download/ -[nvm]: https://github.com/nvm-sh/nvm - ### Clone this repo If you're not a member of the Flutter organization, @@ -164,103 +139,53 @@ following the instructions in [Get the prerequisites](#get-the-prerequisites). dart pub get ``` -3. _Optional:_ We recommend you use `pnpm`, but you can also use `npm`. - Install `pnpm`, an alternative, efficient package manager for - npm packages. If you already have `pnpm`, verify you have the - latest stable version. - - ```console - node --version - ``` - - If you don't already have `pnpm` installed, we recommend - using [`corepack`][] to install and manage `pnpm` versions, - since `corepack` is bundled with most installations of - Node. If you installed `node` using Homebrew, you'll need - to install corepack separately: - - ```console - brew install corepack - ``` - - If you haven't used `corepack` before, you'll need to - first enable it with `corepack enable`. - Then, to install the correct `pnpm` version, from the - root directory of the repository, run `corepack install`: - - ```console - corepack enable; - corepack install - ``` - - To install [`pnpm`][] without using `corepack`, you - can use your preferred [installation method][pnpm-install]. - -5. _(optional)_ Once you have `pnpm` installed and setup, - fetch the site's npm dependencies using `pnpm install`. - We highly recommend you use `pnpm`, but you can also use `npm`. - - ```console - pnpm install - ``` - - Rerun `pnpm install` whenever you incorporate the - latest changes to the `main` branch or if you - experience dependency or import errors when building the site. - -6. From the root directory, run the `dash_site` tool to +3. From the root directory, run the `dash_site` tool to validate your setup and learn about the available commands. - ```console - ./dash_site --help + ```terminal + dart run dash_site --help ``` -7. From the root directory, serve the site locally. +4. From the root directory, serve the site locally. - ```console - ./dash_site serve + ```terminal + dart run dash_site serve ``` This command generates and serves the site on a local port that's printed to your terminal. -8. View your changes in the browser by navigating to . +5. View your changes in the browser by navigating to . - Note the port might be different if `4000` is taken. + Note the port might be different if `8080` is taken. - If you want to check the raw, generated HTML output and structure, - view the `_site` directory in a file explorer or an IDE. - -9. Make your changes to the local repo. +6. Make your changes to the local repo. + To view your changes in the browser, + you'll need to refresh the page. The site should automatically rebuild on most changes, but if something doesn't update, exit the process and rerun the command. - Improvements to this functionality are planned. - Please open a new issue to track the issue if this occurs. -10. Commit your changes to the branch and submit your PR. +7. Commit your changes to the branch and submit your PR. If your change is large, or you'd like to test it, consider [validating your changes](#validate-your-changes). > [!TIP] > To find additional commands that you can run, -> run `./dash_site --help` from the repository's root directory. - -[`corepack`]: https://nodejs.org/api/corepack.html -[`pnpm`]: https://pnpm.io/ -[pnpm-install]: https://pnpm.io/installation +> run `dart run dash_site --help` from the repository's root directory. ## Validate your changes ### Check documentation and example code -If you've made changes to the code in the `/examples` or `/tool` directories, +If you've made changes to the code in +the `/examples`, `/site`, or `/tool` directories, commit your work, then run the following command to verify it is up to date and matches the site standards. -```console -./dash_site check-all +```terminal +dart run dash_site check-all ``` If this script reports any errors or warnings, @@ -286,53 +211,9 @@ how the snippets are copied from the `.dart` files. To resolve this error and update the Markdown snippets to match, from the root of the `website` directory, -run `./dash_site refresh-excerpts`. +run `dart run dash_site refresh-excerpts`. To learn more about creating, editing, and using code excerpts, check out the [excerpt updater package documentation][]. [excerpt updater package documentation]: https://github.com/dart-lang/site-shared/tree/main/pkgs/excerpter#readme - -## [Optional] Deploy to a staging site - -Submitted pull requests can be automatically staged -by a site maintainer. -If you'd like to stage the site yourself though, -you can build a full version and upload it to Firebase. - -1. If you don't already have a Firebase project, - - - Navigate to the [Firebase Console](https://console.firebase.google.com) - and create your own Firebase project (for example, `flutter-dev-staging`). - - - Head back to your local terminal and verify that you're logged in. - - ```console - npm exec -- firebase-tools login - ``` - - - Ensure that your project exists and activate that project: - - ```console - npm exec -- firebase-tools projects:list - npm exec -- firebase-tools use - ``` - -2. From the root directory of the repository, build the site: - - ```console - ./dash_site build - ``` - - This builds the site and copies it to your local `_site` directory. - If that directory previously existed, it will be replaced. - -3. Deploy to your activated Firebase project's default hosting site: - - ```console - npm exec -- firebase-tools deploy --only hosting - ``` - -4. Navigate to your PR on GitHub and include the link of the staged version. - Do consider adding a reference to the commit you staged, - so that reviewers know if any further changes have been made. diff --git a/cloud_build/deploy.yaml b/cloud_build/deploy.yaml index c37e138ffee..6cc3207a5d2 100644 --- a/cloud_build/deploy.yaml +++ b/cloud_build/deploy.yaml @@ -2,15 +2,15 @@ steps: - name: gcr.io/cloud-builders/git args: ['fetch', '--unshallow'] - name: gcr.io/flutter-dev-230821/firebase-ghcli - # Set up, build, then deploy site to production + # Build the site, then deploy it to production. entrypoint: '/bin/bash' args: - '-c' - |- set -e - npm install - npm run build-site-for-production + dart pub get + dart run dash_site build --release firebase deploy --project=flutter-docs-prod --only=hosting options: diff --git a/cloud_build/stage.yaml b/cloud_build/stage.yaml index 81721adc0b3..ffd70b9542b 100644 --- a/cloud_build/stage.yaml +++ b/cloud_build/stage.yaml @@ -7,8 +7,8 @@ steps: - |- set -e - npm install - npm run build-site-for-staging + dart pub get + dart run dash_site build cloud_build/scripts/stage_site_and_comment_on_github.sh secretEnv: ['GH_PAT_TOKEN'] diff --git a/dash_site b/dash_site deleted file mode 100755 index c0703ed3a12..00000000000 --- a/dash_site +++ /dev/null @@ -1,108 +0,0 @@ -#!/bin/bash - -REQUIRED_DART_VERSION="3.9" -REQUIRED_NODE_VERSION="22.12" -REQUIRED_PNPM_VERSION="10.9" - -# Check that the 'dart' command is available on the user's path. -if ! command -v dart &> /dev/null; then - echo "Dart not found. To learn how to setup Dart and Flutter, follow the instructions at https://docs.flutter.dev/get-started." - exit 1 -fi - -# Check that the current version of a tool is the same or -# newer than a required version. -version_is_new_enough() { - required_version="$1" - current_version="$2" - - # Split the version strings into lists based on the dot separators. - IFS='.' read -ra required_list <<< "$required_version" - IFS='.' read -ra current_list <<< "$current_version" - - # Compare each portion of the version number. - for ((i = 0; i < ${#required_list[@]}; i += 1)); do - required_segment="${required_list[i]:-0}" - current_segment="${current_list[i]:-0}" - - if [[ "$required_segment" -gt "$current_segment" ]]; then - # The current version is too low. - return 0 - elif [[ "$required_segment" -lt "$current_segment" ]]; then - # The current version is higher, which is ok. - return 1 - fi - done - - # The current version is (mostly) the same as the required version. - return 1 -} - - -# Determine the available Dart SDK version. -dart_version=$(dart --version | grep -oE 'Dart SDK version: [0-9.]+' | cut -d ' ' -f 4) - -# Validate the version of the installed Dart SDK. -if version_is_new_enough "$REQUIRED_DART_VERSION" "$dart_version"; then - echo "Dart version $dart_version is too low. Version $REQUIRED_DART_VERSION or later is required." - exit 1 -fi - -# Check that the 'node' command is available on the user's path. -if ! command -v node &> /dev/null; then - echo "'node' command not found. To learn how to install and setup Node, reference the repository README." - exit 1 -fi - -# Determine the available Node version. -node_version=$(node --version | cut -d 'v' -f 2) - -# Validate the version of the Node installation. -if version_is_new_enough "$REQUIRED_NODE_VERSION" "$node_version"; then - echo "Node version $node_version is too low. Version $REQUIRED_NODE_VERSION or later is required." - exit 1 -fi - -# Check that the 'npx' command is available on the user's path. -if ! command -v npx &> /dev/null; then - echo "'npx' command from Node not found. Check your Node installation." - exit 1 -fi - -# Run extra logic if the 'pnpm' command is available on the user's path. -if command -v pnpm &> /dev/null; then - # Determine the available pnpm version. - pnpm_version=$(pnpm --version) - - # Validate the version of the pnpm installation. - if version_is_new_enough "$REQUIRED_PNPM_VERSION" "$pnpm_version"; then - echo "pnpm version $pnpm_version is too low. Version $REQUIRED_PNPM_VERSION or later is required." - exit 1 - fi - - # If using pnpm, update the dependencies silently as it is quick. - echo "Verifying npm dependencies are up to date..." - pnpm install --silent -fi - -# Verify that Node packages have been installed. -if [[ ! -d "node_modules" ]]; then - if command -v pnpm &> /dev/null; then - echo "Node packages not found. Installing with 'pnpm install'..." - pnpm install - elif command -v npm &> /dev/null; then - echo "Node packages not found. Installing with 'npm install'..." - npm install - else - echo "Neither 'pnpm' nor 'npm' found. To learn how to setup pnpm, reference the repository README." - exit 1 - fi -fi - -# Verify that Dart dependencies have been retrieved. -if [[ ! -d ".dart_tool" ]]; then - dart pub get -fi - -# Run the Flutter site tool and pass through all arguments. -dart run flutter_site "$@" diff --git a/eleventy.config.ts b/eleventy.config.ts deleted file mode 100644 index bcd8b39c837..00000000000 --- a/eleventy.config.ts +++ /dev/null @@ -1,131 +0,0 @@ -// This file is the entry point for all 11ty configuration. -// It configures the core 11ty behavior and registers -// plugins and customization that live in `/src/_11ty`. - -import { registerFilters } from './src/_11ty/filters.js'; -import { registerShortcodes } from './src/_11ty/shortcodes.js'; -import { markdown } from './src/_11ty/plugins/markdown.js'; -import { configureHighlighting } from './src/_11ty/plugins/highlight.js'; -import { UserConfig } from '@11ty/eleventy'; - -import swcHtml from '@swc/html'; -import yaml from 'js-yaml'; -import { EleventyRenderPlugin } from '@11ty/eleventy'; - -import * as path from 'node:path'; -import * as sass from 'sass'; - -// noinspection JSUnusedGlobalSymbols -export default function (eleventyConfig: UserConfig) { - const isProduction = process.env['PRODUCTION'] === 'true'; - const shouldOptimize = process.env['OPTIMIZE'] === 'true'; - - eleventyConfig.on('eleventy.before', async () => { - await configureHighlighting(markdown); - }); - - eleventyConfig.addGlobalData('isProduction', isProduction); - - eleventyConfig.setLibrary('md', markdown); - - eleventyConfig.addDataExtension('yml,yaml', (contents: string) => - yaml.load(contents), - ); - - eleventyConfig.setLiquidOptions({ - cache: true, - strictFilters: true, - lenientIf: true, - jekyllInclude: true, - }); - - eleventyConfig.addPlugin(EleventyRenderPlugin); - - registerFilters(eleventyConfig); - registerShortcodes(eleventyConfig); - - eleventyConfig.addTemplateFormats('scss'); - eleventyConfig.addWatchTarget('src/_sass'); - eleventyConfig.addExtension('scss', { - outputFileExtension: 'css', - compile: function (inputContent: string, inputPath: string) { - const parsedPath = path.parse(inputPath); - if (parsedPath.name.startsWith('_')) { - return; - } - - const result = sass.compileString(inputContent, { - style: shouldOptimize ? 'compressed' : 'expanded', - quietDeps: true, - loadPaths: [parsedPath.dir, 'src/_sass'], - }); - - const dependencies = result.loadedUrls - .filter( - (loadedUrl) => - loadedUrl.protocol === 'file:' && loadedUrl.pathname !== '', - ) - .map((url) => path.relative('.', url.pathname)); - - this.addDependencies(inputPath, dependencies); - - return () => result.css; - }, - }); - - eleventyConfig.addPassthroughCopy('src/content/assets/js'); - eleventyConfig.addPassthroughCopy('src/content/llms.txt'); - eleventyConfig.addPassthroughCopy('src/content/assets/files', { expand: true }); - eleventyConfig.addPassthroughCopy('src/content/assets/images', { expand: true }); - eleventyConfig.addPassthroughCopy('src/content/f', { - expand: true, - filter: /^(?!_).+/, - }); - eleventyConfig.addPassthroughCopy('src/content/tools/devtools/release-notes', { - filter: (path: string) => path.includes('src') || path.includes('images'), - }); - eleventyConfig.ignores.add("src/content/assets/files/**/*.md"); - - if (shouldOptimize) { - // If building for production, minify/optimize the HTML output. - // Doing so during serving isn't worth the extra build time. - eleventyConfig.addTransform('minify-html', async function (content: string) { - if (this.page.outputPath && this.page.outputPath.endsWith('.html')) { - // Minify the page's content if it's an HTML file. - // Other options can be enabled, but each should be tested. - - const minifiedHtml = await swcHtml.minify(content, { - scriptingEnabled: true, - removeComments: true, - collapseWhitespaces: 'smart', - removeRedundantAttributes: 'smart', - minifyCss: true, - minifyConditionalComments: true, - quotes: true, - }); - - return minifiedHtml.code; - } - - return content; - }); - } - - eleventyConfig.setQuietMode(true); - - eleventyConfig.setServerOptions({ - port: 4000, - watch: ['src/_sass'], - }); - - return { - htmlTemplateEngine: 'liquid', - dir: { - input: 'src/content', - output: '_site', - layouts: '../_layouts', - includes: '../_includes', - data: '../_data', - }, - }; -} diff --git a/firebase.json b/firebase.json index dfc2c8ec228..efc62b4d5ce 100644 --- a/firebase.json +++ b/firebase.json @@ -884,7 +884,7 @@ }, "emulators": { "hosting": { - "port": 5500 + "port": 5502 } } } diff --git a/package.json b/package.json deleted file mode 100644 index c4aa0237bba..00000000000 --- a/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "docs.flutter.dev", - "version": "0.0.0", - "private": true, - "description": "Source for https://docs.flutter.dev", - "type": "module", - "repository": { - "type": "git", - "url": "https://github.com/flutter/website.git" - }, - "engines": { - "node": ">=22.12.0", - "pnpm": ">=10.9.0" - }, - "packageManager": "pnpm@10.17.0", - "scripts": { - "serve": "PRODUCTION=false tsx node_modules/@11ty/eleventy/cmd.cjs --serve --config=eleventy.config.ts", - "build-site-for-staging": "PRODUCTION=false OPTIMIZE=true tsx node_modules/@11ty/eleventy/cmd.cjs --config=eleventy.config.ts", - "build-site-for-production": "PRODUCTION=true OPTIMIZE=true tsx node_modules/@11ty/eleventy/cmd.cjs --config=eleventy.config.ts" - }, - "devDependencies": { - "@11ty/eleventy": "3.1.2", - "@swc/html": "^1.13.5", - "@types/hast": "^3.0.4", - "@types/markdown-it": "^14.1.2", - "@types/node": "^22.18.6", - "hast-util-from-html": "^2.0.3", - "hast-util-select": "^6.0.4", - "hast-util-to-html": "^9.0.5", - "hast-util-to-text": "^4.0.2", - "js-yaml": "^4.1.0", - "markdown-it": "^14.1.0", - "markdown-it-anchor": "^9.2.0", - "markdown-it-attrs": "^4.3.1", - "markdown-it-container": "^4.0.0", - "markdown-it-deflist": "^3.0.0", - "markdown-it-footnote": "^4.0.0", - "sass": "^1.93.0", - "shiki": "^3.13.0", - "tsx": "^4.20.5" - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index c8cbf6efdba..00000000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,2265 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - devDependencies: - '@11ty/eleventy': - specifier: 3.1.2 - version: 3.1.2 - '@swc/html': - specifier: ^1.13.5 - version: 1.13.5 - '@types/hast': - specifier: ^3.0.4 - version: 3.0.4 - '@types/markdown-it': - specifier: ^14.1.2 - version: 14.1.2 - '@types/node': - specifier: ^22.18.6 - version: 22.18.6 - hast-util-from-html: - specifier: ^2.0.3 - version: 2.0.3 - hast-util-select: - specifier: ^6.0.4 - version: 6.0.4 - hast-util-to-html: - specifier: ^9.0.5 - version: 9.0.5 - hast-util-to-text: - specifier: ^4.0.2 - version: 4.0.2 - js-yaml: - specifier: ^4.1.0 - version: 4.1.0 - markdown-it: - specifier: ^14.1.0 - version: 14.1.0 - markdown-it-anchor: - specifier: ^9.2.0 - version: 9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0) - markdown-it-attrs: - specifier: ^4.3.1 - version: 4.3.1(markdown-it@14.1.0) - markdown-it-container: - specifier: ^4.0.0 - version: 4.0.0 - markdown-it-deflist: - specifier: ^3.0.0 - version: 3.0.0 - markdown-it-footnote: - specifier: ^4.0.0 - version: 4.0.0 - sass: - specifier: ^1.93.0 - version: 1.93.0 - shiki: - specifier: ^3.13.0 - version: 3.13.0 - tsx: - specifier: ^4.20.5 - version: 4.20.5 - -packages: - - '@11ty/dependency-tree-esm@2.0.0': - resolution: {integrity: sha512-+4ySOON4aEAiyAGuH6XQJtxpGSpo6nibfG01krgix00sqjhman2+UaDUopq6Ksv8/jBB3hqkhsHe3fDE4z8rbA==} - - '@11ty/dependency-tree@4.0.0': - resolution: {integrity: sha512-PTOnwM8Xt+GdJmwRKg4pZ8EKAgGoK7pedZBfNSOChXu8MYk2FdEsxdJYecX4t62owpGw3xK60q9TQv/5JI59jw==} - - '@11ty/eleventy-dev-server@2.0.8': - resolution: {integrity: sha512-15oC5M1DQlCaOMUq4limKRYmWiGecDaGwryr7fTE/oM9Ix8siqMvWi+I8VjsfrGr+iViDvWcH/TVI6D12d93mA==} - engines: {node: '>=18'} - hasBin: true - - '@11ty/eleventy-plugin-bundle@3.0.7': - resolution: {integrity: sha512-QK1tRFBhQdZASnYU8GMzpTdsMMFLVAkuU0gVVILqNyp09xJJZb81kAS3AFrNrwBCsgLxTdWHJ8N64+OTTsoKkA==} - engines: {node: '>=18'} - - '@11ty/eleventy-utils@2.0.7': - resolution: {integrity: sha512-6QE+duqSQ0GY9rENXYb4iPR4AYGdrFpqnmi59tFp9VrleOl0QSh8VlBr2yd6dlhkdtj7904poZW5PvGr9cMiJQ==} - engines: {node: '>=18'} - - '@11ty/eleventy@3.1.2': - resolution: {integrity: sha512-IcsDlbXnBf8cHzbM1YBv3JcTyLB35EK88QexmVyFdVJVgUU6bh9g687rpxryJirHzo06PuwnYaEEdVZQfIgRGg==} - engines: {node: '>=18'} - hasBin: true - - '@11ty/lodash-custom@4.17.21': - resolution: {integrity: sha512-Mqt6im1xpb1Ykn3nbcCovWXK3ggywRJa+IXIdoz4wIIK+cvozADH63lexcuPpGS/gJ6/m2JxyyXDyupkMr5DHw==} - engines: {node: '>=14'} - - '@11ty/posthtml-urls@1.0.1': - resolution: {integrity: sha512-6EFN/yYSxC/OzYXpq4gXDyDMlX/W+2MgCvvoxf11X1z76bqkqFJ8eep5RiBWfGT5j0323a1pwpelcJJdR46MCw==} - engines: {node: '>= 6'} - - '@11ty/recursive-copy@4.0.2': - resolution: {integrity: sha512-174nFXxL/6KcYbLYpra+q3nDbfKxLxRTNVY1atq2M1pYYiPfHse++3IFNl8mjPFsd7y2qQjxLORzIjHMjL3NDQ==} - engines: {node: '>=18'} - - '@esbuild/aix-ppc64@0.25.10': - resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.10': - resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.10': - resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.10': - resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.10': - resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.10': - resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.10': - resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.10': - resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.10': - resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.10': - resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.10': - resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.10': - resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.10': - resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.10': - resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.10': - resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.10': - resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.10': - resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.10': - resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.10': - resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.10': - resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.10': - resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.10': - resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.10': - resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.10': - resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.10': - resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.10': - resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@parcel/watcher-android-arm64@2.5.1': - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [android] - - '@parcel/watcher-darwin-arm64@2.5.1': - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [darwin] - - '@parcel/watcher-darwin-x64@2.5.1': - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [darwin] - - '@parcel/watcher-freebsd-x64@2.5.1': - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [freebsd] - - '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-win32-arm64@2.5.1': - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] - - '@parcel/watcher-win32-ia32@2.5.1': - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} - engines: {node: '>= 10.0.0'} - cpu: [ia32] - os: [win32] - - '@parcel/watcher-win32-x64@2.5.1': - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [win32] - - '@parcel/watcher@2.5.1': - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} - engines: {node: '>= 10.0.0'} - - '@shikijs/core@3.13.0': - resolution: {integrity: sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA==} - - '@shikijs/engine-javascript@3.13.0': - resolution: {integrity: sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg==} - - '@shikijs/engine-oniguruma@3.13.0': - resolution: {integrity: sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg==} - - '@shikijs/langs@3.13.0': - resolution: {integrity: sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ==} - - '@shikijs/themes@3.13.0': - resolution: {integrity: sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg==} - - '@shikijs/types@3.13.0': - resolution: {integrity: sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw==} - - '@shikijs/vscode-textmate@10.0.2': - resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - - '@sindresorhus/slugify@2.2.1': - resolution: {integrity: sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==} - engines: {node: '>=12'} - - '@sindresorhus/transliterate@1.6.0': - resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==} - engines: {node: '>=12'} - - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - - '@swc/html-darwin-arm64@1.13.5': - resolution: {integrity: sha512-5r4kGFQJm85EKOxSiP9pUT/9T1uq+tx0s5HRqfM/J1hVZmpIq2GudBVYS8CGklVWAVQ0tBHhBuP9SysAb/pcSA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [darwin] - - '@swc/html-darwin-x64@1.13.5': - resolution: {integrity: sha512-bCY0BSfxrmbKpInB/wZFX0DH4hgEQBwWLeKNwZhafIR5R/tvzuiIvb/VdkeKv8+26r2lkedbp+EreCFnDqQ2BQ==} - engines: {node: '>=10'} - cpu: [x64] - os: [darwin] - - '@swc/html-linux-arm-gnueabihf@1.13.5': - resolution: {integrity: sha512-o6TVZERfx7Z8btauYE7nHgMEPPIVemqAZL3ViUTuBK6asF9wfJ4m2YAbsrlzi8xaLgaizWvdUV7W1qE5yfOxPg==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux] - - '@swc/html-linux-arm64-gnu@1.13.5': - resolution: {integrity: sha512-I/Ip5FtCfQ0wYg2MurytkEWPZrFB1SOPOeTNu4n+PAWDBjEcX3q+wgmMpzoGgVljvpEAQviJ+jzRyLW2tDDVHA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - - '@swc/html-linux-arm64-musl@1.13.5': - resolution: {integrity: sha512-q8RTISYZuI5qOR8wEhox2oC+ZBo5IBaT6N43b5W+JRSIMKIsY7hVgC3gSI/tG4/6K14hv2QrqtAUFzVpLwtkyA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - - '@swc/html-linux-x64-gnu@1.13.5': - resolution: {integrity: sha512-YFU0/xVWzjAtg5V6QREW510O5/SNILrm18Vo2qF1bTktCB2eCjNSjCHOdicvPXTImEUlTp0ey6wO+QvEuvRFAg==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - - '@swc/html-linux-x64-musl@1.13.5': - resolution: {integrity: sha512-/ilgZm7umDQTea97FlE0pIcoHTAlICE+aSoVvLi+ONL3wr4g1ebwlgQ5Cxpgp5cxnKeghDYpqP/mFLh+Ztl8DQ==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - - '@swc/html-win32-arm64-msvc@1.13.5': - resolution: {integrity: sha512-aLZvyEhzM6e7E53jelEp9ob/CrZ4K0atmsq+ctsaki8PNOu8shM03CEK1yQNCdZLR1kKkUgytyUVMEbhqz+IQQ==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - - '@swc/html-win32-ia32-msvc@1.13.5': - resolution: {integrity: sha512-51QXTdKMmgRriRmTzH0gkeyHLY4knJdAKEY1kPTBeguXCjgLIUX2nMQd24oe9ovJfPce0NCOmCSrODri8PiduQ==} - engines: {node: '>=10'} - cpu: [ia32] - os: [win32] - - '@swc/html-win32-x64-msvc@1.13.5': - resolution: {integrity: sha512-MnU1fMNZijEKkKTp12SKbNuH7rglgHhXSFZr+zjDhQmtVPEF4goCrBfoY8ZJ4j9FjOGyodFcYH6ulz95l9/QwQ==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - - '@swc/html@1.13.5': - resolution: {integrity: sha512-eVAyb3kk6wltz4FnWNRL06iYnqkQuTfpe5Fin9oLLmcpIYr2DgHcrGgeDJF4vJc9YZwACvEYmV8DC+1NfdzAJQ==} - engines: {node: '>=14'} - - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - - '@types/linkify-it@5.0.0': - resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} - - '@types/markdown-it@14.1.2': - resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} - - '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - - '@types/mdurl@2.0.0': - resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - - '@types/node@22.18.6': - resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==} - - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - - a-sync-waterfall@1.0.1: - resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==} - - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-differ@1.0.0: - resolution: {integrity: sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==} - engines: {node: '>=0.10.0'} - - array-union@1.0.2: - resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} - engines: {node: '>=0.10.0'} - - array-uniq@1.0.3: - resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} - engines: {node: '>=0.10.0'} - - arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} - - asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - bcp-47-match@2.0.3: - resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} - - bcp-47-normalize@2.3.0: - resolution: {integrity: sha512-8I/wfzqQvttUFz7HVJgIZ7+dj3vUaIyIxYXaTRP1YWoSDfzt6TUmxaKZeuXR62qBmYr+nvuWINFRl6pZ5DlN4Q==} - - bcp-47@2.1.0: - resolution: {integrity: sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - comma-separated-tokens@2.0.3: - resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - - commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - - commander@5.1.0: - resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} - engines: {node: '>= 6'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - css-selector-parser@3.1.3: - resolution: {integrity: sha512-gJMigczVZqYAk0hPVzx/M4Hm1D9QOtqkdQk9005TNzDIUGzo5cnHEDiKUT7jGPximL/oYb+LIitcHFQ4aKupxg==} - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - dependency-graph@1.0.0: - resolution: {integrity: sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==} - engines: {node: '>=4'} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - direction@2.0.1: - resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} - hasBin: true - - dom-serializer@1.4.1: - resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@4.3.1: - resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} - engines: {node: '>= 4'} - - domutils@2.8.0: - resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - entities@2.2.0: - resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} - - entities@3.0.1: - resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} - engines: {node: '>=0.12'} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} - - errno@1.0.0: - resolution: {integrity: sha512-3zV5mFS1E8/1bPxt/B0xxzI1snsg3uSCIh6Zo1qKg6iMw93hzPANk9oBFzSFBFrwuVoQuE3rLoouAUfwOAj1wQ==} - hasBin: true - - esbuild@0.25.10: - resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} - engines: {node: '>=18'} - hasBin: true - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - esm-import-transformer@3.0.5: - resolution: {integrity: sha512-1GKLvfuMnnpI75l8c6sHoz0L3Z872xL5akGuBudgqTDPv4Vy6f2Ec7jEMKTxlqWl/3kSvNbHELeimJtnqgYniw==} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - evaluate-value@2.0.0: - resolution: {integrity: sha512-VonfiuDJc0z4sOO7W0Pd130VLsXN6vmBWZlrog1mCb/o7o/Nl5Lr25+Kj/nkCCAhG+zqeeGjxhkK9oHpkgTHhQ==} - engines: {node: '>= 8'} - - extend-shallow@2.0.1: - resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} - engines: {node: '>=0.10.0'} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - filesize@10.1.6: - resolution: {integrity: sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==} - engines: {node: '>= 10.4.0'} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - gray-matter@4.0.3: - resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} - engines: {node: '>=6.0'} - - hast-util-from-html@2.0.3: - resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} - - hast-util-from-parse5@8.0.3: - resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} - - hast-util-has-property@3.0.0: - resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} - - hast-util-is-element@3.0.0: - resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} - - hast-util-parse-selector@4.0.0: - resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - - hast-util-select@6.0.4: - resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} - - hast-util-to-html@9.0.5: - resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} - - hast-util-to-string@3.0.1: - resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} - - hast-util-to-text@4.0.2: - resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} - - hast-util-whitespace@3.0.0: - resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - - hastscript@9.0.1: - resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} - - html-void-elements@3.0.0: - resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - - htmlparser2@7.2.0: - resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==} - - http-equiv-refresh@2.0.1: - resolution: {integrity: sha512-XJpDL/MLkV3dKwLzHwr2dY05dYNfBNlyPu4STQ8WvKCFdc6vC5tPXuq28of663+gHVg03C+16pHHs/+FmmDjcw==} - engines: {node: '>= 6'} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - immutable@5.1.3: - resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - is-alphabetical@2.0.1: - resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - - is-alphanumerical@2.0.1: - resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-decimal@2.0.1: - resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - - is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-json@2.0.1: - resolution: {integrity: sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - iso-639-1@3.1.5: - resolution: {integrity: sha512-gXkz5+KN7HrG0Q5UGqSMO2qB9AsbEeyLP54kF1YrMsIxmu+g4BdB7rflReZTSTZGpfj8wywu6pfPBCylPIzGQA==} - engines: {node: '>=6.0'} - - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - junk@3.1.0: - resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==} - engines: {node: '>=8'} - - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - - kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - - linkify-it@5.0.0: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - - liquidjs@10.21.1: - resolution: {integrity: sha512-NZXmCwv3RG5nire3fmIn9HsOyJX3vo+ptp0yaXUHAMzSNBhx74Hm+dAGJvscUA6lNqbLuYfXgNavRQ9UbUJhQQ==} - engines: {node: '>=14'} - hasBin: true - - list-to-array@1.1.0: - resolution: {integrity: sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g==} - - luxon@3.7.2: - resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} - engines: {node: '>=12'} - - markdown-it-anchor@9.2.0: - resolution: {integrity: sha512-sa2ErMQ6kKOA4l31gLGYliFQrMKkqSO0ZJgGhDHKijPf0pNFM9vghjAh3gn26pS4JDRs7Iwa9S36gxm3vgZTzg==} - peerDependencies: - '@types/markdown-it': '*' - markdown-it: '*' - - markdown-it-attrs@4.3.1: - resolution: {integrity: sha512-/ko6cba+H6gdZ0DOw7BbNMZtfuJTRp9g/IrGIuz8lYc/EfnmWRpaR3CFPnNbVz0LDvF8Gf1hFGPqrQqq7De0rg==} - engines: {node: '>=6'} - peerDependencies: - markdown-it: '>= 9.0.0' - - markdown-it-container@4.0.0: - resolution: {integrity: sha512-HaNccxUH0l7BNGYbFbjmGpf5aLHAMTinqRZQAEQbMr2cdD3z91Q6kIo1oUn1CQndkT03jat6ckrdRYuwwqLlQw==} - - markdown-it-deflist@3.0.0: - resolution: {integrity: sha512-OxPmQ/keJZwbubjiQWOvKLHwpV2wZ5I3Smc81OjhwbfJsjdRrvD5aLTQxmZzzePeO0kbGzAo3Krk4QLgA8PWLg==} - - markdown-it-footnote@4.0.0: - resolution: {integrity: sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==} - - markdown-it@14.1.0: - resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} - hasBin: true - - maximatch@0.1.0: - resolution: {integrity: sha512-9ORVtDUFk4u/NFfo0vG/ND/z7UQCVZBL539YW0+U1I7H1BkZwizcPx5foFv7LCPcBnm2U6RjFnQOsIvN4/Vm2A==} - engines: {node: '>=0.10.0'} - - mdast-util-to-hast@13.2.0: - resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} - - mdurl@2.0.0: - resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} - - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - - moo@0.5.2: - resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==} - - morphdom@2.7.7: - resolution: {integrity: sha512-04GmsiBcalrSCNmzfo+UjU8tt3PhZJKzcOy+r1FlGA7/zri8wre3I1WkYN9PT3sIeIKfW9bpyElA+VzOg2E24g==} - - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - - node-retrieve-globals@6.0.1: - resolution: {integrity: sha512-j0DeFuZ/Wg3VlklfbxUgZF/mdHMTEiEipBb3q0SpMMbHaV3AVfoUQF8UGxh1s/yjqO0TgRZd4Pi/x2yRqoQ4Eg==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - nunjucks@3.2.4: - resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==} - engines: {node: '>= 6.9.0'} - hasBin: true - peerDependencies: - chokidar: ^3.3.0 - peerDependenciesMeta: - chokidar: - optional: true - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - oniguruma-parser@0.12.1: - resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} - - oniguruma-to-es@4.3.3: - resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==} - - parse-srcset@1.0.2: - resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - please-upgrade-node@3.2.0: - resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} - - posthtml-match-helper@2.0.3: - resolution: {integrity: sha512-p9oJgTdMF2dyd7WE54QI1LvpBIkNkbSiiECKezNnDVYhGhD1AaOnAkw0Uh0y5TW+OHO8iBdSqnd8Wkpb6iUqmw==} - engines: {node: '>=18'} - peerDependencies: - posthtml: ^0.16.6 - - posthtml-parser@0.11.0: - resolution: {integrity: sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==} - engines: {node: '>=12'} - - posthtml-render@3.0.0: - resolution: {integrity: sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==} - engines: {node: '>=12'} - - posthtml@0.16.6: - resolution: {integrity: sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==} - engines: {node: '>=12.0.0'} - - property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - - prr@1.0.1: - resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - - punycode.js@2.3.1: - resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} - engines: {node: '>=6'} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - - regex-recursion@6.0.2: - resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} - - regex-utilities@2.3.0: - resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - - regex@6.0.1: - resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - sass@1.93.0: - resolution: {integrity: sha512-CQi5/AzCwiubU3dSqRDJ93RfOfg/hhpW1l6wCIvolmehfwgCI35R/0QDs1+R+Ygrl8jFawwwIojE2w47/mf94A==} - engines: {node: '>=14.0.0'} - hasBin: true - - section-matter@1.0.0: - resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} - engines: {node: '>=4'} - - semver-compare@1.0.0: - resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} - engines: {node: '>= 18'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - shiki@3.13.0: - resolution: {integrity: sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g==} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - slugify@1.6.6: - resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==} - engines: {node: '>=8.0.0'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - ssri@11.0.0: - resolution: {integrity: sha512-aZpUoMN/Jj2MqA4vMCeiKGnc/8SuSyHbGSBdgFbZxP8OJGF/lFkIuElzPxsN0q8TQQ+prw3P4EDfB3TBHHgfXw==} - engines: {node: ^16.14.0 || >=18.0.0} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - - strip-bom-string@1.0.0: - resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} - engines: {node: '>=0.10.0'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - - tsx@4.20.5: - resolution: {integrity: sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==} - engines: {node: '>=18.0.0'} - hasBin: true - - uc.micro@2.1.0: - resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - unist-util-find-after@5.0.0: - resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} - - unist-util-is@6.0.0: - resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} - - unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@6.0.1: - resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} - - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - urlpattern-polyfill@10.1.0: - resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==} - - vfile-location@5.0.3: - resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} - - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} - - vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - - web-namespaces@2.0.1: - resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - -snapshots: - - '@11ty/dependency-tree-esm@2.0.0': - dependencies: - '@11ty/eleventy-utils': 2.0.7 - acorn: 8.15.0 - dependency-graph: 1.0.0 - normalize-path: 3.0.0 - - '@11ty/dependency-tree@4.0.0': - dependencies: - '@11ty/eleventy-utils': 2.0.7 - - '@11ty/eleventy-dev-server@2.0.8': - dependencies: - '@11ty/eleventy-utils': 2.0.7 - chokidar: 3.6.0 - debug: 4.4.3 - finalhandler: 1.3.1 - mime: 3.0.0 - minimist: 1.2.8 - morphdom: 2.7.7 - please-upgrade-node: 3.2.0 - send: 1.2.0 - ssri: 11.0.0 - urlpattern-polyfill: 10.1.0 - ws: 8.18.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@11ty/eleventy-plugin-bundle@3.0.7(posthtml@0.16.6)': - dependencies: - '@11ty/eleventy-utils': 2.0.7 - debug: 4.4.3 - posthtml-match-helper: 2.0.3(posthtml@0.16.6) - transitivePeerDependencies: - - posthtml - - supports-color - - '@11ty/eleventy-utils@2.0.7': {} - - '@11ty/eleventy@3.1.2': - dependencies: - '@11ty/dependency-tree': 4.0.0 - '@11ty/dependency-tree-esm': 2.0.0 - '@11ty/eleventy-dev-server': 2.0.8 - '@11ty/eleventy-plugin-bundle': 3.0.7(posthtml@0.16.6) - '@11ty/eleventy-utils': 2.0.7 - '@11ty/lodash-custom': 4.17.21 - '@11ty/posthtml-urls': 1.0.1 - '@11ty/recursive-copy': 4.0.2 - '@sindresorhus/slugify': 2.2.1 - bcp-47-normalize: 2.3.0 - chokidar: 3.6.0 - debug: 4.4.3 - dependency-graph: 1.0.0 - entities: 6.0.1 - filesize: 10.1.6 - gray-matter: 4.0.3 - iso-639-1: 3.1.5 - js-yaml: 4.1.0 - kleur: 4.1.5 - liquidjs: 10.21.1 - luxon: 3.7.2 - markdown-it: 14.1.0 - minimist: 1.2.8 - moo: 0.5.2 - node-retrieve-globals: 6.0.1 - nunjucks: 3.2.4(chokidar@3.6.0) - picomatch: 4.0.3 - please-upgrade-node: 3.2.0 - posthtml: 0.16.6 - posthtml-match-helper: 2.0.3(posthtml@0.16.6) - semver: 7.7.2 - slugify: 1.6.6 - tinyglobby: 0.2.15 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@11ty/lodash-custom@4.17.21': {} - - '@11ty/posthtml-urls@1.0.1': - dependencies: - evaluate-value: 2.0.0 - http-equiv-refresh: 2.0.1 - list-to-array: 1.1.0 - parse-srcset: 1.0.2 - - '@11ty/recursive-copy@4.0.2': - dependencies: - errno: 1.0.0 - junk: 3.1.0 - maximatch: 0.1.0 - slash: 3.0.0 - - '@esbuild/aix-ppc64@0.25.10': - optional: true - - '@esbuild/android-arm64@0.25.10': - optional: true - - '@esbuild/android-arm@0.25.10': - optional: true - - '@esbuild/android-x64@0.25.10': - optional: true - - '@esbuild/darwin-arm64@0.25.10': - optional: true - - '@esbuild/darwin-x64@0.25.10': - optional: true - - '@esbuild/freebsd-arm64@0.25.10': - optional: true - - '@esbuild/freebsd-x64@0.25.10': - optional: true - - '@esbuild/linux-arm64@0.25.10': - optional: true - - '@esbuild/linux-arm@0.25.10': - optional: true - - '@esbuild/linux-ia32@0.25.10': - optional: true - - '@esbuild/linux-loong64@0.25.10': - optional: true - - '@esbuild/linux-mips64el@0.25.10': - optional: true - - '@esbuild/linux-ppc64@0.25.10': - optional: true - - '@esbuild/linux-riscv64@0.25.10': - optional: true - - '@esbuild/linux-s390x@0.25.10': - optional: true - - '@esbuild/linux-x64@0.25.10': - optional: true - - '@esbuild/netbsd-arm64@0.25.10': - optional: true - - '@esbuild/netbsd-x64@0.25.10': - optional: true - - '@esbuild/openbsd-arm64@0.25.10': - optional: true - - '@esbuild/openbsd-x64@0.25.10': - optional: true - - '@esbuild/openharmony-arm64@0.25.10': - optional: true - - '@esbuild/sunos-x64@0.25.10': - optional: true - - '@esbuild/win32-arm64@0.25.10': - optional: true - - '@esbuild/win32-ia32@0.25.10': - optional: true - - '@esbuild/win32-x64@0.25.10': - optional: true - - '@parcel/watcher-android-arm64@2.5.1': - optional: true - - '@parcel/watcher-darwin-arm64@2.5.1': - optional: true - - '@parcel/watcher-darwin-x64@2.5.1': - optional: true - - '@parcel/watcher-freebsd-x64@2.5.1': - optional: true - - '@parcel/watcher-linux-arm-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-arm-musl@2.5.1': - optional: true - - '@parcel/watcher-linux-arm64-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-arm64-musl@2.5.1': - optional: true - - '@parcel/watcher-linux-x64-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-x64-musl@2.5.1': - optional: true - - '@parcel/watcher-win32-arm64@2.5.1': - optional: true - - '@parcel/watcher-win32-ia32@2.5.1': - optional: true - - '@parcel/watcher-win32-x64@2.5.1': - optional: true - - '@parcel/watcher@2.5.1': - dependencies: - detect-libc: 1.0.3 - is-glob: 4.0.3 - micromatch: 4.0.8 - node-addon-api: 7.1.1 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 - optional: true - - '@shikijs/core@3.13.0': - dependencies: - '@shikijs/types': 3.13.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - hast-util-to-html: 9.0.5 - - '@shikijs/engine-javascript@3.13.0': - dependencies: - '@shikijs/types': 3.13.0 - '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 4.3.3 - - '@shikijs/engine-oniguruma@3.13.0': - dependencies: - '@shikijs/types': 3.13.0 - '@shikijs/vscode-textmate': 10.0.2 - - '@shikijs/langs@3.13.0': - dependencies: - '@shikijs/types': 3.13.0 - - '@shikijs/themes@3.13.0': - dependencies: - '@shikijs/types': 3.13.0 - - '@shikijs/types@3.13.0': - dependencies: - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - '@shikijs/vscode-textmate@10.0.2': {} - - '@sindresorhus/slugify@2.2.1': - dependencies: - '@sindresorhus/transliterate': 1.6.0 - escape-string-regexp: 5.0.0 - - '@sindresorhus/transliterate@1.6.0': - dependencies: - escape-string-regexp: 5.0.0 - - '@swc/counter@0.1.3': {} - - '@swc/html-darwin-arm64@1.13.5': - optional: true - - '@swc/html-darwin-x64@1.13.5': - optional: true - - '@swc/html-linux-arm-gnueabihf@1.13.5': - optional: true - - '@swc/html-linux-arm64-gnu@1.13.5': - optional: true - - '@swc/html-linux-arm64-musl@1.13.5': - optional: true - - '@swc/html-linux-x64-gnu@1.13.5': - optional: true - - '@swc/html-linux-x64-musl@1.13.5': - optional: true - - '@swc/html-win32-arm64-msvc@1.13.5': - optional: true - - '@swc/html-win32-ia32-msvc@1.13.5': - optional: true - - '@swc/html-win32-x64-msvc@1.13.5': - optional: true - - '@swc/html@1.13.5': - dependencies: - '@swc/counter': 0.1.3 - optionalDependencies: - '@swc/html-darwin-arm64': 1.13.5 - '@swc/html-darwin-x64': 1.13.5 - '@swc/html-linux-arm-gnueabihf': 1.13.5 - '@swc/html-linux-arm64-gnu': 1.13.5 - '@swc/html-linux-arm64-musl': 1.13.5 - '@swc/html-linux-x64-gnu': 1.13.5 - '@swc/html-linux-x64-musl': 1.13.5 - '@swc/html-win32-arm64-msvc': 1.13.5 - '@swc/html-win32-ia32-msvc': 1.13.5 - '@swc/html-win32-x64-msvc': 1.13.5 - - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/linkify-it@5.0.0': {} - - '@types/markdown-it@14.1.2': - dependencies: - '@types/linkify-it': 5.0.0 - '@types/mdurl': 2.0.0 - - '@types/mdast@4.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/mdurl@2.0.0': {} - - '@types/node@22.18.6': - dependencies: - undici-types: 6.21.0 - - '@types/unist@3.0.3': {} - - '@ungap/structured-clone@1.3.0': {} - - a-sync-waterfall@1.0.1: {} - - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - array-differ@1.0.0: {} - - array-union@1.0.2: - dependencies: - array-uniq: 1.0.3 - - array-uniq@1.0.3: {} - - arrify@1.0.1: {} - - asap@2.0.6: {} - - balanced-match@1.0.2: {} - - bcp-47-match@2.0.3: {} - - bcp-47-normalize@2.3.0: - dependencies: - bcp-47: 2.1.0 - bcp-47-match: 2.0.3 - - bcp-47@2.1.0: - dependencies: - is-alphabetical: 2.0.1 - is-alphanumerical: 2.0.1 - is-decimal: 2.0.1 - - binary-extensions@2.3.0: {} - - boolbase@1.0.0: {} - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - ccount@2.0.1: {} - - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - comma-separated-tokens@2.0.3: {} - - commander@10.0.1: {} - - commander@5.1.0: {} - - concat-map@0.0.1: {} - - css-selector-parser@3.1.3: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - depd@2.0.0: {} - - dependency-graph@1.0.0: {} - - dequal@2.0.3: {} - - detect-libc@1.0.3: - optional: true - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - direction@2.0.1: {} - - dom-serializer@1.4.1: - dependencies: - domelementtype: 2.3.0 - domhandler: 4.3.1 - entities: 2.2.0 - - domelementtype@2.3.0: {} - - domhandler@4.3.1: - dependencies: - domelementtype: 2.3.0 - - domutils@2.8.0: - dependencies: - dom-serializer: 1.4.1 - domelementtype: 2.3.0 - domhandler: 4.3.1 - - ee-first@1.1.1: {} - - encodeurl@2.0.0: {} - - entities@2.2.0: {} - - entities@3.0.1: {} - - entities@4.5.0: {} - - entities@6.0.1: {} - - errno@1.0.0: - dependencies: - prr: 1.0.1 - - esbuild@0.25.10: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.10 - '@esbuild/android-arm': 0.25.10 - '@esbuild/android-arm64': 0.25.10 - '@esbuild/android-x64': 0.25.10 - '@esbuild/darwin-arm64': 0.25.10 - '@esbuild/darwin-x64': 0.25.10 - '@esbuild/freebsd-arm64': 0.25.10 - '@esbuild/freebsd-x64': 0.25.10 - '@esbuild/linux-arm': 0.25.10 - '@esbuild/linux-arm64': 0.25.10 - '@esbuild/linux-ia32': 0.25.10 - '@esbuild/linux-loong64': 0.25.10 - '@esbuild/linux-mips64el': 0.25.10 - '@esbuild/linux-ppc64': 0.25.10 - '@esbuild/linux-riscv64': 0.25.10 - '@esbuild/linux-s390x': 0.25.10 - '@esbuild/linux-x64': 0.25.10 - '@esbuild/netbsd-arm64': 0.25.10 - '@esbuild/netbsd-x64': 0.25.10 - '@esbuild/openbsd-arm64': 0.25.10 - '@esbuild/openbsd-x64': 0.25.10 - '@esbuild/openharmony-arm64': 0.25.10 - '@esbuild/sunos-x64': 0.25.10 - '@esbuild/win32-arm64': 0.25.10 - '@esbuild/win32-ia32': 0.25.10 - '@esbuild/win32-x64': 0.25.10 - - escape-html@1.0.3: {} - - escape-string-regexp@5.0.0: {} - - esm-import-transformer@3.0.5: - dependencies: - acorn: 8.15.0 - - esprima@4.0.1: {} - - etag@1.8.1: {} - - evaluate-value@2.0.0: {} - - extend-shallow@2.0.1: - dependencies: - is-extendable: 0.1.1 - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - filesize@10.1.6: {} - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - finalhandler@1.3.1: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - fresh@2.0.0: {} - - fsevents@2.3.3: - optional: true - - get-tsconfig@4.10.1: - dependencies: - resolve-pkg-maps: 1.0.0 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - gray-matter@4.0.3: - dependencies: - js-yaml: 3.14.1 - kind-of: 6.0.3 - section-matter: 1.0.0 - strip-bom-string: 1.0.0 - - hast-util-from-html@2.0.3: - dependencies: - '@types/hast': 3.0.4 - devlop: 1.1.0 - hast-util-from-parse5: 8.0.3 - parse5: 7.3.0 - vfile: 6.0.3 - vfile-message: 4.0.3 - - hast-util-from-parse5@8.0.3: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - devlop: 1.1.0 - hastscript: 9.0.1 - property-information: 7.1.0 - vfile: 6.0.3 - vfile-location: 5.0.3 - web-namespaces: 2.0.1 - - hast-util-has-property@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-is-element@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-parse-selector@4.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-select@6.0.4: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - bcp-47-match: 2.0.3 - comma-separated-tokens: 2.0.3 - css-selector-parser: 3.1.3 - devlop: 1.1.0 - direction: 2.0.1 - hast-util-has-property: 3.0.0 - hast-util-to-string: 3.0.1 - hast-util-whitespace: 3.0.0 - nth-check: 2.1.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - unist-util-visit: 5.0.0 - zwitch: 2.0.4 - - hast-util-to-html@9.0.5: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - comma-separated-tokens: 2.0.3 - hast-util-whitespace: 3.0.0 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - stringify-entities: 4.0.4 - zwitch: 2.0.4 - - hast-util-to-string@3.0.1: - dependencies: - '@types/hast': 3.0.4 - - hast-util-to-text@4.0.2: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - hast-util-is-element: 3.0.0 - unist-util-find-after: 5.0.0 - - hast-util-whitespace@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hastscript@9.0.1: - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - hast-util-parse-selector: 4.0.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - - html-void-elements@3.0.0: {} - - htmlparser2@7.2.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 4.3.1 - domutils: 2.8.0 - entities: 3.0.1 - - http-equiv-refresh@2.0.1: {} - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - immutable@5.1.3: {} - - inherits@2.0.4: {} - - is-alphabetical@2.0.1: {} - - is-alphanumerical@2.0.1: - dependencies: - is-alphabetical: 2.0.1 - is-decimal: 2.0.1 - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-decimal@2.0.1: {} - - is-extendable@0.1.1: {} - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-json@2.0.1: {} - - is-number@7.0.0: {} - - iso-639-1@3.1.5: {} - - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - junk@3.1.0: {} - - kind-of@6.0.3: {} - - kleur@4.1.5: {} - - linkify-it@5.0.0: - dependencies: - uc.micro: 2.1.0 - - liquidjs@10.21.1: - dependencies: - commander: 10.0.1 - - list-to-array@1.1.0: {} - - luxon@3.7.2: {} - - markdown-it-anchor@9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0): - dependencies: - '@types/markdown-it': 14.1.2 - markdown-it: 14.1.0 - - markdown-it-attrs@4.3.1(markdown-it@14.1.0): - dependencies: - markdown-it: 14.1.0 - - markdown-it-container@4.0.0: {} - - markdown-it-deflist@3.0.0: {} - - markdown-it-footnote@4.0.0: {} - - markdown-it@14.1.0: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - - maximatch@0.1.0: - dependencies: - array-differ: 1.0.0 - array-union: 1.0.2 - arrify: 1.0.1 - minimatch: 3.1.2 - - mdast-util-to-hast@13.2.0: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.0 - devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.1 - trim-lines: 3.0.1 - unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 - vfile: 6.0.3 - - mdurl@2.0.0: {} - - micromark-util-character@2.1.1: - dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-encode@2.0.1: {} - - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 - - micromark-util-symbol@2.0.1: {} - - micromark-util-types@2.0.2: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - optional: true - - mime-db@1.54.0: {} - - mime-types@3.0.1: - dependencies: - mime-db: 1.54.0 - - mime@3.0.0: {} - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.12 - - minimist@1.2.8: {} - - minipass@7.1.2: {} - - moo@0.5.2: {} - - morphdom@2.7.7: {} - - ms@2.0.0: {} - - ms@2.1.3: {} - - node-addon-api@7.1.1: - optional: true - - node-retrieve-globals@6.0.1: - dependencies: - acorn: 8.15.0 - acorn-walk: 8.3.4 - esm-import-transformer: 3.0.5 - - normalize-path@3.0.0: {} - - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - - nunjucks@3.2.4(chokidar@3.6.0): - dependencies: - a-sync-waterfall: 1.0.1 - asap: 2.0.6 - commander: 5.1.0 - optionalDependencies: - chokidar: 3.6.0 - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - oniguruma-parser@0.12.1: {} - - oniguruma-to-es@4.3.3: - dependencies: - oniguruma-parser: 0.12.1 - regex: 6.0.1 - regex-recursion: 6.0.2 - - parse-srcset@1.0.2: {} - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - parseurl@1.3.3: {} - - picomatch@2.3.1: {} - - picomatch@4.0.3: {} - - please-upgrade-node@3.2.0: - dependencies: - semver-compare: 1.0.0 - - posthtml-match-helper@2.0.3(posthtml@0.16.6): - dependencies: - posthtml: 0.16.6 - - posthtml-parser@0.11.0: - dependencies: - htmlparser2: 7.2.0 - - posthtml-render@3.0.0: - dependencies: - is-json: 2.0.1 - - posthtml@0.16.6: - dependencies: - posthtml-parser: 0.11.0 - posthtml-render: 3.0.0 - - property-information@7.1.0: {} - - prr@1.0.1: {} - - punycode.js@2.3.1: {} - - range-parser@1.2.1: {} - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - - readdirp@4.1.2: {} - - regex-recursion@6.0.2: - dependencies: - regex-utilities: 2.3.0 - - regex-utilities@2.3.0: {} - - regex@6.0.1: - dependencies: - regex-utilities: 2.3.0 - - resolve-pkg-maps@1.0.0: {} - - sass@1.93.0: - dependencies: - chokidar: 4.0.3 - immutable: 5.1.3 - source-map-js: 1.2.1 - optionalDependencies: - '@parcel/watcher': 2.5.1 - - section-matter@1.0.0: - dependencies: - extend-shallow: 2.0.1 - kind-of: 6.0.3 - - semver-compare@1.0.0: {} - - semver@7.7.2: {} - - send@1.2.0: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.0 - mime-types: 3.0.1 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - setprototypeof@1.2.0: {} - - shiki@3.13.0: - dependencies: - '@shikijs/core': 3.13.0 - '@shikijs/engine-javascript': 3.13.0 - '@shikijs/engine-oniguruma': 3.13.0 - '@shikijs/langs': 3.13.0 - '@shikijs/themes': 3.13.0 - '@shikijs/types': 3.13.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - slash@3.0.0: {} - - slugify@1.6.6: {} - - source-map-js@1.2.1: {} - - space-separated-tokens@2.0.2: {} - - sprintf-js@1.0.3: {} - - ssri@11.0.0: - dependencies: - minipass: 7.1.2 - - statuses@2.0.1: {} - - statuses@2.0.2: {} - - stringify-entities@4.0.4: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - - strip-bom-string@1.0.0: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - toidentifier@1.0.1: {} - - trim-lines@3.0.1: {} - - tsx@4.20.5: - dependencies: - esbuild: 0.25.10 - get-tsconfig: 4.10.1 - optionalDependencies: - fsevents: 2.3.3 - - uc.micro@2.1.0: {} - - undici-types@6.21.0: {} - - unist-util-find-after@5.0.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.0 - - unist-util-is@6.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position@5.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-visit-parents@6.0.1: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.0 - - unist-util-visit@5.0.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 - - unpipe@1.0.0: {} - - urlpattern-polyfill@10.1.0: {} - - vfile-location@5.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile: 6.0.3 - - vfile-message@4.0.3: - dependencies: - '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 - - vfile@6.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile-message: 4.0.3 - - web-namespaces@2.0.1: {} - - ws@8.18.3: {} - - zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index 012c404565c..00000000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,3 +0,0 @@ -onlyBuiltDependencies: - - '@parcel/watcher' - - esbuild diff --git a/pubspec.yaml b/pubspec.yaml index 55ee1ac6e6c..f5f7a1f7080 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,8 @@ name: docs_flutter_dev publish_to: none environment: - sdk: ^3.9.0 + sdk: ^3.9.2 workspace: - - tool/flutter_site + - site + - tool/dash_site diff --git a/site/README.md b/site/README.md new file mode 100644 index 00000000000..2799cc39977 --- /dev/null +++ b/site/README.md @@ -0,0 +1,19 @@ +This directory contains the [Dart][], [Jaspr][], and [Jaspr Content][] based +implementation of the [docs.flutter.dev documentation website][docs]. + +[Dart]: https://dart.dev +[Jaspr]: https://docs.jaspr.site +[Jaspr Content]: https://docs.jaspr.site/content +[docs]: https://docs.flutter.dev + +## Usage + +The site should be run with the `dart run dash_site` tool +from the root of the repository. +Some relevant commands include: + +- **Serve:** `dart run dash_site serve` +- **Build:** `dart run dash_site build` +- **Clean:** `dart run dash_site clean` + +Run `dart run dash_site --help` to learn what other commands are available. diff --git a/site/analysis_options.yaml b/site/analysis_options.yaml new file mode 100644 index 00000000000..95c3595413a --- /dev/null +++ b/site/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:analysis_defaults/analysis.yaml + +formatter: + trailing_commas: preserve diff --git a/site/build.yaml b/site/build.yaml new file mode 100644 index 00000000000..26840b528a4 --- /dev/null +++ b/site/build.yaml @@ -0,0 +1,29 @@ +builders: + stylesHashBuilder: + import: 'package:docs_flutter_dev_site/builders.dart' + builder_factories: [ 'stylesHashBuilder' ] + build_extensions: + "web/assets/css/main.css": + - "lib/src/style_hash.dart" + auto_apply: root_package + build_to: source + +targets: + $default: + builders: + build_web_compilers:entrypoint: + dev_options: + compilers: + dartdevc: + release_options: + # Use production compilers for release builds and + # ensure kReleaseMode in jaspr is enabled. + compilers: + dart2js: + args: + - --no-source-maps + - -O4 + - -Djaspr.flags.release=true + # Disable for now. + # dart2wasm: + # args: [-O2, -Djaspr.flags.release=true] diff --git a/src/_sass/site.scss b/site/lib/_sass/_site.scss similarity index 100% rename from src/_sass/site.scss rename to site/lib/_sass/_site.scss diff --git a/src/_sass/base/_base.scss b/site/lib/_sass/base/_base.scss similarity index 95% rename from src/_sass/base/_base.scss rename to site/lib/_sass/base/_base.scss index e6e998da1cd..fcddcfd5513 100644 --- a/src/_sass/base/_base.scss +++ b/site/lib/_sass/base/_base.scss @@ -6,6 +6,17 @@ body { line-height: 1.5; background-color: var(--site-base-bgColor); color: var(--site-base-fgColor); + + // The top TOC is not shown on narrow screens. + @media (min-width: 1200px) { + --site-subheader-height: 0rem; + } + + // If the TOC is disabled, reduce the subheader height to + // ensure offset calculations are still correct. + &[data-toc="false"], &.no-toc { + --site-subheader-height: 0rem; + } } *:focus-visible { @@ -27,10 +38,6 @@ body { flex-grow: 1; align-items: flex-start; justify-content: space-between; - - &.no-toc { - --site-subheader-height: 0rem; - } } h2 { @@ -390,14 +397,15 @@ ol.steps { } main { - ol + img, ul + img, ol + p, ul + p, p + p + img, - ul + p:last-child { + ol + img, ul + img, ol + p, ul + p, p + p + img { margin-bottom: 1rem; } -} -td ol, td ul, td dl, td p { - margin-bottom: 0; + td { + > *:last-child { + margin-bottom: 0; + } + } } p + ul, p + ol, p + dl { @@ -405,10 +413,6 @@ p + ul, p + ol, p + dl { margin-block-end: 0.75rem; } -td ol, td ul, td dl, td p { - margin-bottom: 0; -} - .figure-caption { font-size: .875rem; font-style: italic; @@ -468,6 +472,7 @@ td ol, td ul, td dl, td p { .video-intro { font-weight: 500; + font-size: 1.125rem; padding: 0 0.75rem; text-wrap: pretty; } diff --git a/src/_sass/base/_mixins.scss b/site/lib/_sass/base/_mixins.scss similarity index 100% rename from src/_sass/base/_mixins.scss rename to site/lib/_sass/base/_mixins.scss diff --git a/src/_sass/base/_print-overrides.scss b/site/lib/_sass/base/_print-overrides.scss similarity index 90% rename from src/_sass/base/_print-overrides.scss rename to site/lib/_sass/base/_print-overrides.scss index 4b122a6c89c..fa5ac4e8a80 100644 --- a/src/_sass/base/_print-overrides.scss +++ b/site/lib/_sass/base/_print-overrides.scss @@ -1,14 +1,14 @@ // Overrides for printing so only page content is printed @media print { // Ignore navigation elements and other non-necessary interactive ones - .site-header, .subnav, .site-footer, .site-sidebar, .navbar, + #site-header, .subnav, .site-footer, #sidenav, .navbar, #site-toc--side, #page-github-links, #cookie-notice, .site-banner, .code-excerpt__copy-btn, .breadcrumb { display: none !important; } // Make sure content fills up 100% of width - .site-content { + #page-content { max-width: 100% !important; margin-left: 0; padding-left: 0; diff --git a/src/_sass/base/_reset.scss b/site/lib/_sass/base/_reset.scss similarity index 100% rename from src/_sass/base/_reset.scss rename to site/lib/_sass/base/_reset.scss diff --git a/src/_sass/base/_root.scss b/site/lib/_sass/base/_root.scss similarity index 95% rename from src/_sass/base/_root.scss rename to site/lib/_sass/base/_root.scss index f1b050ce476..d6faf890bf9 100644 --- a/src/_sass/base/_root.scss +++ b/site/lib/_sass/base/_root.scss @@ -161,11 +161,11 @@ body { --site-alert-warning-color: #cea11f; --site-alert-error-color: #ff5d5d; - .shiki, .shiki span { - color: var(--shiki-dark) !important; - font-style: var(--shiki-dark-font-style) !important; - font-weight: var(--shiki-dark-font-weight) !important; - text-decoration: var(--shiki-dark-text-decoration) !important; + .opal, .opal span { + color: var(--opal-dark-color) !important; + font-style: var(--opal-dark-font-style) !important; + font-weight: var(--opal-dark-font-weight) !important; + text-decoration: var(--opal-dark-text-decoration) !important; } .light-mode-visible { diff --git a/src/_sass/base/_utils.scss b/site/lib/_sass/base/_utils.scss similarity index 100% rename from src/_sass/base/_utils.scss rename to site/lib/_sass/base/_utils.scss diff --git a/src/_sass/components/_alert.scss b/site/lib/_sass/components/_alert.scss similarity index 100% rename from src/_sass/components/_alert.scss rename to site/lib/_sass/components/_alert.scss diff --git a/src/_sass/components/_banner.scss b/site/lib/_sass/components/_banner.scss similarity index 100% rename from src/_sass/components/_banner.scss rename to site/lib/_sass/components/_banner.scss diff --git a/src/_sass/components/_books.scss b/site/lib/_sass/components/_books.scss similarity index 100% rename from src/_sass/components/_books.scss rename to site/lib/_sass/components/_books.scss diff --git a/src/_sass/components/_button.scss b/site/lib/_sass/components/_button.scss similarity index 100% rename from src/_sass/components/_button.scss rename to site/lib/_sass/components/_button.scss index 101a97fbd59..784c029a4b8 100644 --- a/src/_sass/components/_button.scss +++ b/site/lib/_sass/components/_button.scss @@ -36,13 +36,13 @@ a, button { padding: 0.5rem 1rem; text-decoration: none; cursor: pointer; - user-select: none; } &.filled-button { background-color: var(--site-filledButton-bgColor); color: var(--site-filledButton-fgColor); outline-offset: 2px; + user-select: none; &:hover { @include mixins.interaction-style(8%); diff --git a/src/_sass/components/_card.scss b/site/lib/_sass/components/_card.scss similarity index 100% rename from src/_sass/components/_card.scss rename to site/lib/_sass/components/_card.scss diff --git a/src/_sass/components/_code.scss b/site/lib/_sass/components/_code.scss similarity index 80% rename from src/_sass/components/_code.scss rename to site/lib/_sass/components/_code.scss index fc9ea2ad0f8..fde9f54d64c 100644 --- a/src/_sass/components/_code.scss +++ b/site/lib/_sass/components/_code.scss @@ -31,9 +31,10 @@ main kbd { } pre { - margin-bottom: 1rem; + margin: 0 0 1rem; + font-size: 0.9375rem; + font-weight: 400; padding: 1.25rem; - overflow: auto; > code { // Undo the core `code` styles. @@ -45,6 +46,9 @@ pre { border-radius: unset; word-break: normal; white-space: pre; + font-family: var(--site-code-fontFamily); + color: var(--site-base-fgColor); + --opal-dark-color: var(--site-base-fgColor); } a { @@ -73,8 +77,10 @@ pre { display: inline-block; padding-left: 1.25rem; padding-right: 1.25rem; + width: 100%; + display: block; min-width: 100%; - border-left: 2px solid transparent; + border-left: 2px solid rgba(0, 0, 0, 0); &.highlighted-line { background: var(--site-primary-color-highlight); @@ -143,36 +149,6 @@ pre { } } -.code-inner-buttons { - position: absolute; - top: 6px; - right: 6px; - z-index: var(--site-z-floating); - - display: flex; - flex-direction: row; - gap: 0.2rem; - - button { - padding: 0.2rem; - appearance: none; - border: none; - color: var(--site-base-fgColor-alt); - background: none; - opacity: 0; - transition: opacity 0.4s; - - &:hover, &:focus { - color: var(--site-link-fgColor); - opacity: 1; - } - - &:active { - color: var(--site-link-fgColor-active); - } - } -} - .code-block-language { font-family: var(--site-code-fontFamily); user-select: none; @@ -185,24 +161,6 @@ pre { top: 3px; right: 6px; z-index: var(--site-z-floating); - - .highlight-languages .language-dart & { - color: var(--site-primary-color); - } - - .highlight-languages .language-js & { - color: #f1a85a; - } - - .highlight-languages .language-swift & { - color: #f05137; - } - - .highlight-languages :not(.has-tag) & { - font-size: 0.875rem; - left: 6px; - right: unset; - } } .code-block-tag { @@ -215,8 +173,10 @@ pre { } .code-block-wrapper { - margin-bottom: 1rem; + margin-block-start: 1rem; + margin-block-end: 1rem; border: 1px solid var(--site-inset-borderColor); + background-color: var(--site-inset-bgColor); .code-block-header { background-color: var(--site-raised-bgColor); @@ -230,27 +190,46 @@ pre { .code-block-body { position: relative; - background-color: var(--site-inset-bgColor); + background: none; + + .copy-button { + position: absolute; + top: 6px; + right: 6px; + z-index: 10; + + opacity: 0; + transition: opacity 0.4s; + + &:hover, &:focus, &:active { + opacity: 1; + } + } &:hover, &:focus-within { .code-block-language { opacity: 0; } - .code-inner-buttons button { + .copy-button { opacity: 1; } } } &:has(:focus-visible) { - border-color: #1389FD; + border-color: var(--site-primary-color); } pre { margin: 0; padding-right: 0; padding-left: 0; + overflow-x: auto; + + &:not([lang="console"]) { + line-height: 1.8; + } code { display: block; diff --git a/src/_sass/components/_collapsible.scss b/site/lib/_sass/components/_collapsible.scss similarity index 99% rename from src/_sass/components/_collapsible.scss rename to site/lib/_sass/components/_collapsible.scss index 5725c4416a4..c29cff727a1 100644 --- a/src/_sass/components/_collapsible.scss +++ b/site/lib/_sass/components/_collapsible.scss @@ -1,5 +1,4 @@ .collapsible-section { - .collapsible-button { background-color: #eee; color: #444; @@ -19,5 +18,4 @@ display: block; } } - -} \ No newline at end of file +} diff --git a/src/_sass/components/_content.scss b/site/lib/_sass/components/_content.scss similarity index 98% rename from src/_sass/components/_content.scss rename to site/lib/_sass/components/_content.scss index 68d31a74028..3598d7668a1 100644 --- a/src/_sass/components/_content.scss +++ b/site/lib/_sass/components/_content.scss @@ -1,4 +1,4 @@ -.site-content { +#page-content { display: flex; flex-direction: column; justify-content: center; @@ -15,6 +15,7 @@ } article { + flex-grow: 1; min-width: 8rem; max-width: 960px; min-height: calc(100vh - var(--site-header-height) - var(--site-subheader-height)); @@ -50,7 +51,7 @@ } } - #site-header-wrapper { + #site-content-title { margin-block-end: 1rem; h1 { diff --git a/src/_sass/components/_cookie-notice.scss b/site/lib/_sass/components/_cookie-notice.scss similarity index 56% rename from src/_sass/components/_cookie-notice.scss rename to site/lib/_sass/components/_cookie-notice.scss index 861323c7158..8f6af0e6dea 100644 --- a/src/_sass/components/_cookie-notice.scss +++ b/site/lib/_sass/components/_cookie-notice.scss @@ -1,8 +1,8 @@ #cookie-notice { display: none; justify-content: center; - background-color: var(--site-base-bgColor); - padding: 1.5rem; + background-color: var(--site-header-bgColor); + padding: 1.25rem; position: fixed; bottom: 0; width: 100%; @@ -21,22 +21,33 @@ &.show { display: flex; - animation-duration: 500ms; - animation-delay: 200ms; - animation-name: fadein; - animation-iteration-count: 1; - animation-timing-function: ease; - animation-fill-mode: forwards; + animation: fadein 500ms ease 200ms 1 forwards; } .container { display: flex; - justify-content: space-between; + justify-content: center; align-items: center; max-width: 1080px; min-width: 0; width: auto; gap: 1.5rem; + flex-wrap: wrap; + + @media (min-width: 576px) { + flex-wrap: nowrap; + } + + .button-group { + display: flex; + flex-direction: row; + gap: 0.75rem; + align-items: center; + + .text-button { + color: var(--site-link-fgColor); + } + } p { font-size: 1rem; diff --git a/site/lib/_sass/components/_dropdown.scss b/site/lib/_sass/components/_dropdown.scss new file mode 100644 index 00000000000..c412916ca40 --- /dev/null +++ b/site/lib/_sass/components/_dropdown.scss @@ -0,0 +1,65 @@ +@use '../base/mixins'; + +.dropdown { + .dropdown-content { + display: none; + position: absolute; + background-color: var(--site-header-bgColor); + color: var(--site-base-fgColor); + box-shadow: 0 6px 18px 0 rgba(0, 0, 0, 0.2); + border-radius: calc(var(--site-radius) * 1.25); + width: max-content; + border: var(--site-outline-variant) 1px solid; + z-index: var(--site-z-dropdown); + + .dropdown-divider { + background-color: var(--site-outline-variant); + border-radius: 0.5rem; + height: 0.125rem; + margin: 0.25rem; + padding: 0 !important; + } + + .dropdown-menu { + padding: 0.2rem; + + ul { + display: flex; + flex-direction: column; + list-style: none; + padding: 0; + margin: 0; + + li { + padding: 0.25rem; + + a, button { + display: flex; + align-items: center; + flex-direction: row; + width: 100%; + gap: 0.4rem; + padding: 0.2rem 0.4rem; + border-radius: var(--site-radius); + + text-decoration: none; + + &:hover { + @include mixins.interaction-style(4%); + } + + &:active { + @include mixins.interaction-style(6%); + } + } + } + } + } + } + + &[data-expanded="true"] { + .dropdown-content { + display: block; + } + } +} diff --git a/src/_sass/components/_expansion-list.scss b/site/lib/_sass/components/_expansion-list.scss similarity index 99% rename from src/_sass/components/_expansion-list.scss rename to site/lib/_sass/components/_expansion-list.scss index 3a46b1cc3f6..fe8800dea10 100644 --- a/src/_sass/components/_expansion-list.scss +++ b/site/lib/_sass/components/_expansion-list.scss @@ -114,6 +114,7 @@ .expansion-panel-body { display: none; margin: auto; + padding-top: .75rem; width: 90%; border-top: .05rem solid var(--site-card-borderColor); diff --git a/src/_sass/components/_footer.scss b/site/lib/_sass/components/_footer.scss similarity index 63% rename from src/_sass/components/_footer.scss rename to site/lib/_sass/components/_footer.scss index 9d6209e0573..604e71a379f 100644 --- a/src/_sass/components/_footer.scss +++ b/site/lib/_sass/components/_footer.scss @@ -53,6 +53,7 @@ flex-wrap: wrap; justify-content: center; gap: 1rem; + margin-top: 1.5rem; a { display: inline-flex; @@ -69,26 +70,56 @@ } } - @media (max-width: 768px) { - margin-top: 24px; + @media (min-width: 768px) { + margin-top: 0; } } - ul { - list-style-type: none; - margin: 0; - padding: 0; + .footer-technology { + margin-top: 1rem; + + .jaspr-badge-link { + span:last-child { + display: none; + } + + &:hover { + span:first-child { + display: none; + } - li { - display: inline; - margin-left: 16px; + span:last-child { + display: initial; + } + } } + } - @media (max-width: 768px) { - margin-top: 12px; + .footer-utility-links { + @media (min-width: 768px) { + text-align: right; + } + + ul { + list-style-type: none; + margin: 12px 0 0; + padding: 0; + + li { + display: inline; + margin-left: 16px; + + &:first-child { + margin-left: 0; + } + } + + @media (min-width: 768px) { + margin-top: 0; - li:first-child { - margin-left: 0; + li:first-child { + margin-left: 16px; + } } } } @@ -98,7 +129,7 @@ font-family: var(--site-ui-fontFamily); &:hover, &:focus, &:active { - color: #fff; + color: var(--site-filledButton-fgColor); } } -} +} \ No newline at end of file diff --git a/src/_sass/components/_header.scss b/site/lib/_sass/components/_header.scss similarity index 86% rename from src/_sass/components/_header.scss rename to site/lib/_sass/components/_header.scss index 5d757f057d4..1617b237bd1 100644 --- a/src/_sass/components/_header.scss +++ b/site/lib/_sass/components/_header.scss @@ -1,4 +1,4 @@ -.site-header { +#site-header { background-color: var(--site-header-bgColor); font-family: var(--site-ui-fontFamily); position: sticky; @@ -65,7 +65,7 @@ } } - &__search { + #header-search { display: none; position: relative; align-items: center; @@ -82,31 +82,27 @@ font: 28px/1 var(--site-icon-fontFamily); pointer-events: none; position: absolute; - left: 1.25rem; + left: 1rem; } &:hover::before { color: var(--site-base-fgColor); } - &:focus-within::before { - //left: 1rem; - } - } - - &__searchfield { - border: 0; - font-size: 1rem; - transition: width .35s ease-in-out; - width: 24px; - cursor: pointer; - border-radius: 24px; - padding: 0.5rem 0.5rem 0.5rem 3rem; - background: none; - - &:focus { - width: 220px; - cursor: auto; + input { + border: 0; + font-size: 1rem; + transition: width .35s ease-in-out; + width: 24px; + cursor: pointer; + border-radius: 24px; + padding: 0.5rem 0.5rem 0.5rem 3rem; + background: none; + + &:focus { + width: 220px; + cursor: auto; + } } } @@ -114,7 +110,7 @@ display: none; @media (min-width: 320px) { - display: unset; + display: flex; } @media (min-width: 576px) { diff --git a/src/_sass/components/_icons.scss b/site/lib/_sass/components/_icons.scss similarity index 100% rename from src/_sass/components/_icons.scss rename to site/lib/_sass/components/_icons.scss diff --git a/src/_sass/components/_misc.scss b/site/lib/_sass/components/_misc.scss similarity index 97% rename from src/_sass/components/_misc.scss rename to site/lib/_sass/components/_misc.scss index 2c60ef8ab94..6322a02cea7 100644 --- a/src/_sass/components/_misc.scss +++ b/site/lib/_sass/components/_misc.scss @@ -1,4 +1,4 @@ -.site-content p.install-help { +#page-content p.install-help { text-align: right; margin-block-start: -2.5rem; diff --git a/src/_sass/components/_next-prev-nav.scss b/site/lib/_sass/components/_next-prev-nav.scss similarity index 100% rename from src/_sass/components/_next-prev-nav.scss rename to site/lib/_sass/components/_next-prev-nav.scss diff --git a/src/_sass/components/_os-selector.scss b/site/lib/_sass/components/_os-selector.scss similarity index 100% rename from src/_sass/components/_os-selector.scss rename to site/lib/_sass/components/_os-selector.scss diff --git a/src/_sass/components/_pill.scss b/site/lib/_sass/components/_pill.scss similarity index 69% rename from src/_sass/components/_pill.scss rename to site/lib/_sass/components/_pill.scss index e58992442fd..0ab0453b731 100644 --- a/src/_sass/components/_pill.scss +++ b/site/lib/_sass/components/_pill.scss @@ -1,3 +1,5 @@ +@use 'sass:color'; + .rrec-pill { border-radius: 8px; margin: 0.5rem; @@ -10,15 +12,15 @@ // Green &.success { - background: darken(#f1fbf9, 10%); + background: color.scale(#f1fbf9, $lightness: -10%); color: #155723; } // Blue &.info { $info-bg: #e7f8ff; - background: darken($info-bg, 10%); - color: darken($info-bg, 60%); + background: color.scale($info-bg, $lightness: -10%); + color: color.scale($info-bg, $lightness: -60%); } } @@ -37,17 +39,17 @@ // compatible with dark mode. &.flutter-blue { - color: lighten(#E7F8FF, 10%); + color: color.scale(#E7F8FF, $lightness: 10%); background: #0468D7; } &.teal { - color: lighten(#B8EDE1, 10%); + color: color.scale(#B8EDE1, $lightness: 10%); background: #158477; } &.purple { - color: lighten(#C6BAFA, 10%); + color: color.scale(#C6BAFA, $lightness: 10%); background: #6200EE; } } diff --git a/src/_sass/components/_side-menu.scss b/site/lib/_sass/components/_side-menu.scss similarity index 100% rename from src/_sass/components/_side-menu.scss rename to site/lib/_sass/components/_side-menu.scss diff --git a/src/_sass/components/_sidebar.scss b/site/lib/_sass/components/_sidebar.scss similarity index 100% rename from src/_sass/components/_sidebar.scss rename to site/lib/_sass/components/_sidebar.scss diff --git a/src/_sass/components/_site-switcher.scss b/site/lib/_sass/components/_site-switcher.scss similarity index 100% rename from src/_sass/components/_site-switcher.scss rename to site/lib/_sass/components/_site-switcher.scss diff --git a/src/_sass/components/_tabs.scss b/site/lib/_sass/components/_tabs.scss similarity index 98% rename from src/_sass/components/_tabs.scss rename to site/lib/_sass/components/_tabs.scss index da1f0b56b6c..4a03086f17a 100644 --- a/src/_sass/components/_tabs.scss +++ b/site/lib/_sass/components/_tabs.scss @@ -22,7 +22,7 @@ ul.nav-tabs { border-radius: $wrapper-radius; background-color: var(--site-raised-bgColor); gap: 0.5rem; - overflow-x: scroll; + overflow-x: auto; scrollbar-width: thin; li { diff --git a/site/lib/_sass/components/_theming.scss b/site/lib/_sass/components/_theming.scss new file mode 100644 index 00000000000..68ada3c8a3d --- /dev/null +++ b/site/lib/_sass/components/_theming.scss @@ -0,0 +1,15 @@ +#theme-switcher { + position: relative; + + > .dropdown-content { + right: -0.5rem; + + .material-symbols { + font-size: 20px; + } + } + + button[aria-selected="true"] { + background-color: var(--site-primary-color-highlight); + } +} diff --git a/src/_sass/components/_toc.scss b/site/lib/_sass/components/_toc.scss similarity index 99% rename from src/_sass/components/_toc.scss rename to site/lib/_sass/components/_toc.scss index a51efb059cf..b3012a90d33 100644 --- a/src/_sass/components/_toc.scss +++ b/site/lib/_sass/components/_toc.scss @@ -87,7 +87,7 @@ min-width: 100%; max-width: 100%; - overflow-y: scroll; + overflow-y: auto; scrollbar-width: thin; overscroll-behavior: contain; diff --git a/src/_sass/components/_trailing.scss b/site/lib/_sass/components/_trailing.scss similarity index 56% rename from src/_sass/components/_trailing.scss rename to site/lib/_sass/components/_trailing.scss index 2882a361ab8..923d6d791d8 100644 --- a/src/_sass/components/_trailing.scss +++ b/site/lib/_sass/components/_trailing.scss @@ -30,39 +30,13 @@ } } - .initial-feedback { - .feedback-buttons { - display: flex; - flex-direction: row; - gap: 0.5rem; - - span.material-symbols { - font-size: 20px; - } - } - } - - .good-feedback, .bad-feedback { - display: none; - } - - &.feedback-up { - .initial-feedback { - display: none; - } - - .good-feedback { - display: flex; - } - } - - &.feedback-down { - .initial-feedback { - display: none; - } + .feedback-buttons { + display: flex; + flex-direction: row; + gap: 0.5rem; - .bad-feedback { - display: flex; + span.material-symbols { + font-size: 20px; } } } @@ -70,5 +44,5 @@ #page-github-links { font-style: italic; font-size: 0.75rem; - margin-bottom: 0; + margin: 0; } diff --git a/src/_sass/pages/_learning-resources-index.scss b/site/lib/_sass/pages/_learning-resources-index.scss similarity index 100% rename from src/_sass/pages/_learning-resources-index.scss rename to site/lib/_sass/pages/_learning-resources-index.scss diff --git a/src/_sass/pages/_not-found.scss b/site/lib/_sass/pages/_not-found.scss similarity index 100% rename from src/_sass/pages/_not-found.scss rename to site/lib/_sass/pages/_not-found.scss diff --git a/src/_sass/pages/_search.scss b/site/lib/_sass/pages/_search.scss similarity index 100% rename from src/_sass/pages/_search.scss rename to site/lib/_sass/pages/_search.scss diff --git a/site/lib/builders.dart b/site/lib/builders.dart new file mode 100644 index 00000000000..efc2ba9250d --- /dev/null +++ b/site/lib/builders.dart @@ -0,0 +1,9 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:build/build.dart'; + +import 'src/builders/styles_hash_builder.dart' show StylesHashBuilder; + +Builder stylesHashBuilder(BuilderOptions _) => const StylesHashBuilder(); diff --git a/site/lib/jaspr_options.dart b/site/lib/jaspr_options.dart new file mode 100644 index 00000000000..831027edc6c --- /dev/null +++ b/site/lib/jaspr_options.dart @@ -0,0 +1,142 @@ +// dart format off +// ignore_for_file: type=lint + +// GENERATED FILE, DO NOT MODIFY +// Generated with jaspr_builder + +import 'package:jaspr/jaspr.dart'; +import 'package:docs_flutter_dev_site/src/client/global_scripts.dart' + as prefix0; +import 'package:docs_flutter_dev_site/src/components/common/client/cookie_notice.dart' + as prefix1; +import 'package:docs_flutter_dev_site/src/components/common/client/copy_button.dart' + as prefix2; +import 'package:docs_flutter_dev_site/src/components/common/client/download_latest_button.dart' + as prefix3; +import 'package:docs_flutter_dev_site/src/components/common/client/feedback.dart' + as prefix4; +import 'package:docs_flutter_dev_site/src/components/common/client/on_this_page_button.dart' + as prefix5; +import 'package:docs_flutter_dev_site/src/components/common/client/os_selector.dart' + as prefix6; +import 'package:docs_flutter_dev_site/src/components/dartpad/dartpad_injector.dart' + as prefix7; +import 'package:docs_flutter_dev_site/src/components/layout/menu_toggle.dart' + as prefix8; +import 'package:docs_flutter_dev_site/src/components/layout/site_switcher.dart' + as prefix9; +import 'package:docs_flutter_dev_site/src/components/layout/theme_switcher.dart' + as prefix10; +import 'package:docs_flutter_dev_site/src/components/pages/archive_table.dart' + as prefix11; +import 'package:docs_flutter_dev_site/src/components/pages/learning_resource_filters.dart' + as prefix12; +import 'package:docs_flutter_dev_site/src/components/pages/learning_resource_filters_sidebar.dart' + as prefix13; + +/// Default [JasprOptions] for use with your jaspr project. +/// +/// Use this to initialize jaspr **before** calling [runApp]. +/// +/// Example: +/// ```dart +/// import 'jaspr_options.dart'; +/// +/// void main() { +/// Jaspr.initializeApp( +/// options: defaultJasprOptions, +/// ); +/// +/// runApp(...); +/// } +/// ``` +JasprOptions get defaultJasprOptions => JasprOptions( + clients: { + prefix0.GlobalScripts: ClientTarget( + 'src/client/global_scripts', + ), + + prefix1.CookieNotice: ClientTarget( + 'src/components/common/client/cookie_notice', + ), + + prefix2.CopyButton: ClientTarget( + 'src/components/common/client/copy_button', + params: _prefix2CopyButton, + ), + + prefix3.DownloadLatestButton: ClientTarget( + 'src/components/common/client/download_latest_button', + params: _prefix3DownloadLatestButton, + ), + + prefix4.FeedbackComponent: ClientTarget( + 'src/components/common/client/feedback', + params: _prefix4FeedbackComponent, + ), + + prefix5.OnThisPageButton: ClientTarget( + 'src/components/common/client/on_this_page_button', + ), + + prefix6.OsSelector: ClientTarget( + 'src/components/common/client/os_selector', + ), + + prefix7.DartPadInjector: ClientTarget( + 'src/components/dartpad/dartpad_injector', + params: _prefix7DartPadInjector, + ), + + prefix8.MenuToggle: ClientTarget( + 'src/components/layout/menu_toggle', + ), + + prefix9.SiteSwitcher: ClientTarget( + 'src/components/layout/site_switcher', + ), + + prefix10.ThemeSwitcher: ClientTarget( + 'src/components/layout/theme_switcher', + ), + + prefix11.ArchiveTable: ClientTarget( + 'src/components/pages/archive_table', + params: _prefix11ArchiveTable, + ), + + prefix12.LearningResourceFilters: + ClientTarget( + 'src/components/pages/learning_resource_filters', + ), + + prefix13.LearningResourceFiltersSidebar: + ClientTarget( + 'src/components/pages/learning_resource_filters_sidebar', + ), + }, + styles: () => [], +); + +Map _prefix2CopyButton(prefix2.CopyButton c) => { + 'toCopy': c.toCopy, + 'buttonText': c.buttonText, + 'classes': c.classes, + 'title': c.title, +}; +Map _prefix3DownloadLatestButton( + prefix3.DownloadLatestButton c, +) => {'os': c.os, 'arch': c.arch}; +Map _prefix4FeedbackComponent(prefix4.FeedbackComponent c) => { + 'issueUrl': c.issueUrl, +}; +Map _prefix7DartPadInjector(prefix7.DartPadInjector c) => { + 'title': c.title, + 'theme': c.theme, + 'height': c.height, + 'runAutomatically': c.runAutomatically, +}; +Map _prefix11ArchiveTable(prefix11.ArchiveTable c) => { + 'os': c.os, + 'channel': c.channel, +}; diff --git a/site/lib/main.dart b/site/lib/main.dart new file mode 100644 index 00000000000..04c6037d586 --- /dev/null +++ b/site/lib/main.dart @@ -0,0 +1,106 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/server.dart'; +import 'package:jaspr_content/jaspr_content.dart'; +import 'package:jaspr_content/theme.dart'; +import 'package:path/path.dart' as path; + +import 'jaspr_options.dart'; // Generated. Do not remove or edit. +import 'src/components/common/card.dart'; +import 'src/components/common/client/download_latest_button.dart'; +import 'src/components/common/client/os_selector.dart'; +import 'src/components/common/dash_image.dart'; +import 'src/components/common/tabs.dart'; +import 'src/components/common/youtube_embed.dart'; +import 'src/components/pages/archive_table.dart'; +import 'src/components/pages/devtools_release_notes_index.dart'; +import 'src/components/pages/expansion_list.dart'; +import 'src/components/pages/learning_resource_index.dart'; +import 'src/extensions/registry.dart'; +import 'src/layouts/catalog_page_layout.dart'; +import 'src/layouts/doc_layout.dart'; +import 'src/layouts/toc_layout.dart'; +import 'src/loaders/data_processor.dart'; +import 'src/markdown/markdown_parser.dart'; +import 'src/pages/custom_pages.dart'; +import 'src/pages/robots_txt.dart'; +import 'src/templating/dash_template_engine.dart'; +import 'src/util.dart'; + +void main() { + // Initializes the server environment with the generated default options. + Jaspr.initializeApp(options: defaultJasprOptions); + + runApp(_docsFlutterDevSite); +} + +Component get _docsFlutterDevSite => ContentApp.custom( + eagerlyLoadAllPages: true, + loaders: [ + FilesystemLoader( + path.join(siteSrcDirectoryPath, 'content'), + keepSuffixPattern: _passThroughPattern, + ), + MemoryLoader(pages: allMemoryPages), + ], + configResolver: PageConfig.all( + dataLoaders: [ + FilesystemDataLoader(path.join(siteSrcDirectoryPath, 'data')), + DataProcessor(), + ], + templateEngine: DashTemplateEngine( + partialDirectoryPath: path.canonicalize( + path.join(siteSrcDirectoryPath, '_includes'), + ), + ), + parsers: const [ + DashMarkdownParser(), + HtmlParser(), + ], + rawOutputPattern: _passThroughPattern, + extensions: allNodeProcessingExtensions, + components: _embeddableComponents, + layouts: const [DocLayout(), TocLayout(), CatalogPageLayout()], + theme: const ContentTheme.none(), + secondaryOutputs: [const RobotsTxtOutput(), MarkdownOutput()], + ), +); + +final RegExp _passThroughPattern = RegExp(r'.*\.(txt|json|pdf)$'); + +/// Custom "components" that can be used from Markdown files. +List get _embeddableComponents => [ + const DashTabs(), + const DashImage(), + const YoutubeEmbed(), + CustomComponent( + pattern: RegExp('OSSelector', caseSensitive: false), + builder: (_, _, _) => const OsSelector(), + ), + CustomComponent( + pattern: RegExp('Card', caseSensitive: false), + builder: (_, attrs, child) => Card.fromAttributes(attrs, child), + ), + CustomComponent( + pattern: RegExp('LearningResourceIndex', caseSensitive: false), + builder: (_, _, _) => LearningResourceIndex(), + ), + CustomComponent( + pattern: RegExp('ArchiveTable'), + builder: (_, attrs, _) => ArchiveTable.fromAttributes(attrs), + ), + CustomComponent( + pattern: RegExp('DownloadLatestButton', caseSensitive: false), + builder: (_, attrs, _) => DownloadLatestButton.fromAttributes(attrs), + ), + CustomComponent( + pattern: RegExp('ExpansionList', caseSensitive: false), + builder: (_, attrs, _) => ExpansionList.fromAttributes(attrs), + ), + CustomComponent( + pattern: RegExp('DevToolsReleaseNotesIndex', caseSensitive: false), + builder: (_, _, _) => const DevToolsReleaseNotesIndex(), + ), +]; diff --git a/site/lib/src/analytics/analytics.dart b/site/lib/src/analytics/analytics.dart new file mode 100644 index 00000000000..8042bef976d --- /dev/null +++ b/site/lib/src/analytics/analytics.dart @@ -0,0 +1,21 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'analytics_server.dart' + if (dart.library.js_interop) 'analytics_web.dart'; + +/// Used to report analytic events. +final analytics = AnalyticsImplementation(); + +/// Contains methods for reporting analytics events. +abstract class Analytics { + @internal + void sendEvent(String eventName, Map parameters); + + void sendFeedback(bool helpful) { + sendEvent('feedback', {'feedback_type': helpful ? 'up' : 'down'}); + } +} diff --git a/site/lib/src/analytics/analytics_server.dart b/site/lib/src/analytics/analytics_server.dart new file mode 100644 index 00000000000..f023c091406 --- /dev/null +++ b/site/lib/src/analytics/analytics_server.dart @@ -0,0 +1,18 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'analytics.dart'; + +/// Server implementation of [Analytics]. +/// +/// Don't use directly. Access through [analytics] instead. +@internal +final class AnalyticsImplementation extends Analytics { + @override + void sendEvent(String eventName, Map parameters) { + // Ignore on the server. + } +} diff --git a/site/lib/src/analytics/analytics_web.dart b/site/lib/src/analytics/analytics_web.dart new file mode 100644 index 00000000000..568e56e3c9c --- /dev/null +++ b/site/lib/src/analytics/analytics_web.dart @@ -0,0 +1,32 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart'; +import 'package:universal_web/js_interop.dart'; +import 'package:universal_web/web.dart' as web; + +import '../util.dart'; +import 'analytics.dart'; + +/// Web implementation of [Analytics]. +/// +/// Don't use directly. Access through [analytics] instead. +@internal +final class AnalyticsImplementation extends Analytics { + @override + void sendEvent(String eventName, Map parameters) { + if (!productionBuild) { + return; + } + final dataLayer = web.window['dataLayer']; + if (dataLayer.isA()) { + (dataLayer as JSArray).toDart.add( + { + 'event': eventName, + ...parameters, + }.jsify(), + ); + } + } +} diff --git a/site/lib/src/builders/styles_hash_builder.dart b/site/lib/src/builders/styles_hash_builder.dart new file mode 100644 index 00000000000..daf129da280 --- /dev/null +++ b/site/lib/src/builders/styles_hash_builder.dart @@ -0,0 +1,38 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'package:build/build.dart'; +import 'package:crypto/crypto.dart'; + +class StylesHashBuilder implements Builder { + const StylesHashBuilder(); + + @override + Map> get buildExtensions => { + 'web/assets/css/main.css': ['lib/src/style_hash.dart'], + }; + + @override + Future build(BuildStep buildStep) async { + final inputId = buildStep.inputId; + final bytes = await buildStep.readAsBytes(inputId); + final digest = sha256.convert(bytes); + final hashString = base64.encode(digest.bytes).substring(0, 12); + + final outputContent = + """ +// Generated by docs_flutter_dev_site|stylesHashBuilder. Do not edit. +// dart format off + +/// The generated hash of the `main.css` file. +const generatedStylesHash = '$hashString'; +"""; + + await buildStep.writeAsString( + buildStep.allowedOutputs.single, + outputContent, + ); + } +} diff --git a/site/lib/src/client/global_scripts.dart b/site/lib/src/client/global_scripts.dart new file mode 100644 index 00000000000..997a2321973 --- /dev/null +++ b/site/lib/src/client/global_scripts.dart @@ -0,0 +1,407 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:universal_web/js_interop.dart'; +import 'package:universal_web/web.dart' as web; + +import '../util.dart'; + +/// Global scripts converted from JS. +/// +/// These are temporary until they can be integrated with their +/// relevant Jaspr components. +@client +final class GlobalScripts extends StatefulComponent { + @override + State createState() => _GlobalScriptsState(); +} + +final class _GlobalScriptsState extends State { + @override + void initState() { + if (kIsWeb) { + // Run setup if DOM is loaded, otherwise do it after it has loaded. + if (web.document.readyState == 'loading') { + web.document.addEventListener('DOMContentLoaded', _setUpSite.toJS); + } else { + _setUpSite(); + } + } + + super.initState(); + } + + @override + Component build(BuildContext context) => const Component.empty(); +} + +void _setUpSite() { + _setUpSearchKeybindings(); + _setUpTabs(); + _setUpCollapsibleElements(); + _setUpPlatformKeys(); + _setUpToc(); +} + +void _setUpSearchKeybindings() { + web.document.addEventListener('keydown', _handleSearchShortcut.toJS); +} + +void _handleSearchShortcut(web.Event event) { + final keyboardEvent = event as web.KeyboardEvent; + final activeElement = web.document.activeElement; + + // Don't intercept if typing in an input field or not pressing slash key. + if (activeElement.isA() || + activeElement.isA() || + keyboardEvent.code != 'Slash') { + return; + } + + final web.Element? parentElement; + // If the sidebar is open, focus its search field. + if (web.document.body!.classList.contains('open_menu')) { + parentElement = web.document.getElementById('sidenav'); + } else { + // If the page has a search field in the body, focus that. + if (web.document.getElementById('in-content-search') + case final bodySearch?) { + parentElement = bodySearch; + } else { + // Otherwise, fallback to the top navbar search field. + parentElement = web.document.getElementById('header-search'); + } + } + + // If we found any search field, focus it. + if (parentElement?.querySelector('.search-field') + case final web.HTMLElement searchField) { + searchField.focus(); + // Prevent the initial slash from showing up in the search field. + event.preventDefault(); + } +} + +// TODO(parlough): Migrate interactivity of tabs to the Jaspr components. +/// Set up interactivity of tabs created with +/// the `` and `` custom components. +void _setUpTabs() { + _updateTabsFromQueryParameters(); + + final tabsWrappers = web.document.querySelectorAll('.tabs-wrapper'); + + for ( + var wrapperIndex = 0; + wrapperIndex < tabsWrappers.length; + wrapperIndex++ + ) { + final element = tabsWrappers.item(wrapperIndex) as web.HTMLElement; + final saveKey = element.dataset['tabSaveKey']; + final localStorageKey = saveKey.isNotEmpty ? 'tab-save-$saveKey' : null; + final tabs = element.querySelectorAll(':scope > .nav-tabs a.nav-link'); + web.HTMLElement? tabToChangeTo; + + for (var tabIndex = 0; tabIndex < tabs.length; tabIndex++) { + final tabElement = tabs.item(tabIndex) as web.HTMLElement; + final saveId = tabElement.dataset['tabSaveId']; + + void handleClick(web.Event event) { + event.preventDefault(); + final currentSaveKey = element.dataset['tabSaveKey']; + final currentSaveId = tabElement.dataset['tabSaveId']; + if (currentSaveKey.isNotEmpty && currentSaveId.isNotEmpty) { + // If the tab wrapper and this tab have a save key and ID defined, + // switch other tabs to the tab with the same ID. + _findAndActivateTabsWithSaveId(currentSaveKey, currentSaveId); + web.window.localStorage.setItem( + 'tab-save-$currentSaveKey', + currentSaveId, + ); + } else { + _clearActiveTabs(tabs); + _setActiveTab(tabElement); + } + } + + tabElement.addEventListener('click', handleClick.toJS); + + // If a tab was previously specified as selected in local storage, + // save a reference to it that can be switched to later. + if (saveId.isNotEmpty && + localStorageKey != null && + web.window.localStorage.getItem(localStorageKey) == saveId) { + tabToChangeTo = tabElement; + } + } + + if (tabToChangeTo != null) { + tabToChangeTo.click(); + } else if (saveKey == 'dev-os') { + // If this tab wrapper is for the archive page, + // and no tab was retrieved from local storage, + // switch to the tab for the current OS. + var currentOperatingSystem = getOS(); + if (currentOperatingSystem == null) { + currentOperatingSystem = OperatingSystem.windows; + } else if (currentOperatingSystem == OperatingSystem.chromeos) { + // ChromeOS uses the Linux tab. + currentOperatingSystem = OperatingSystem.linux; + } + + _activateTabWithSaveId(element, currentOperatingSystem.name); + } + } +} + +/// Apply force overrides from query parameters to saved tabs. +void _updateTabsFromQueryParameters() { + final currentUrl = Uri.parse(web.window.location.href); + final originalQueryParameters = currentUrl.queryParameters; + final updatedQueryParameters = {...originalQueryParameters}; + + for (final MapEntry(:key, :value) in originalQueryParameters.entries) { + if (key.startsWith('tab-save-')) { + web.window.localStorage.setItem(key, value); + updatedQueryParameters.remove(key); + } + } + + if (originalQueryParameters.length != updatedQueryParameters.length) { + // If the query parameters were updated, update the user's URL. + web.window.history.replaceState( + null, + '', + currentUrl.replace(queryParameters: updatedQueryParameters).toString(), + ); + } +} + +void _clearActiveTabs(web.NodeList tabs) { + for (var tabIndex = 0; tabIndex < tabs.length; tabIndex++) { + final tabElement = tabs.item(tabIndex) as web.HTMLElement; + tabElement.classList.remove('active'); + tabElement.ariaSelected = 'false'; + final panelId = '${tabElement.id}-panel'; + final panel = web.document.getElementById(panelId); + panel?.classList.remove('active'); + } +} + +void _setActiveTab(web.HTMLElement tab) { + tab.classList.add('active'); + tab.ariaSelected = 'true'; + final panelId = '${tab.id}-panel'; + final panel = web.document.getElementById(panelId); + panel?.classList.add('active'); +} + +void _findAndActivateTabsWithSaveId(String saveKey, String saveId) { + final tabsWrappers = web.document.querySelectorAll( + '.tabs-wrapper[data-tab-save-key="$saveKey"]', + ); + + for ( + var wrapperIndex = 0; + wrapperIndex < tabsWrappers.length; + wrapperIndex++ + ) { + final wrapper = tabsWrappers.item(wrapperIndex) as web.HTMLElement; + + _activateTabWithSaveId(wrapper, saveId); + } +} + +void _activateTabWithSaveId(web.HTMLElement tabWrapper, String saveId) { + final tabsNav = tabWrapper.querySelector(':scope > .nav-tabs'); + if (tabsNav == null) return; + + if (tabsNav.querySelector('a.nav-link[data-tab-save-id="$saveId"]') + case final web.HTMLElement tabToActivate) { + final tabs = tabsNav.querySelectorAll('a.nav-link'); + _clearActiveTabs(tabs); + _setActiveTab(tabToActivate); + } +} + +void _setUpCollapsibleElements() { + final toggles = web.document.querySelectorAll('[data-toggle="collapse"]'); + for (var toggleIndex = 0; toggleIndex < toggles.length; toggleIndex += 1) { + final toggle = toggles.item(toggleIndex) as web.Element; + + final targetSelector = toggle.getAttribute('data-target'); + if (targetSelector == null) return; + final target = web.document.querySelector(targetSelector); + if (target == null) return; + + void handleClick(web.Event e) { + if (toggle.classList.contains('collapsed')) { + toggle.classList.remove('collapsed'); + toggle.ariaExpanded = 'true'; + + target.classList.add('show'); + } else { + toggle.classList.add('collapsed'); + toggle.ariaExpanded = 'false'; + + target.classList.remove('show'); + } + + e.preventDefault(); + } + + toggle.addEventListener('click', handleClick.toJS); + } +} + +void _setUpPlatformKeys() { + final os = getOS(); + // Use Command key for macOS, Control key for other OS. + final specialKey = switch (os) { + OperatingSystem.macos => 'Command', + _ => 'Control', + }; + final keys = web.document.querySelectorAll('kbd.special-key'); + for (var i = 0; i < keys.length; i += 1) { + final element = keys.item(i) as web.Element; + element.textContent = specialKey; + } +} + +/// Adjusts the behavior of the table of contents (TOC) on the page. +/// +/// This function enables a "scrollspy" feature on the TOC, +/// where the active link in the TOC is updated +/// based on the currently visible section in the page. +/// +/// Enables a "back to top" button in the TOC header. +void _setUpToc() { + _setUpTocActiveObserver(); + _setUpInlineTocDropdown(); +} + +void _setUpInlineTocDropdown() { + final inlineToc = web.document.getElementById('toc-top'); + if (inlineToc == null) return; + + final dropdownButton = inlineToc.querySelector('.dropdown-button'); + final dropdownMenu = inlineToc.querySelector('.dropdown-content'); + if (dropdownButton == null || dropdownMenu == null) return; + + void closeMenu() { + inlineToc.setAttribute('data-expanded', 'false'); + dropdownButton.ariaExpanded = 'false'; + } + + dropdownButton.addEventListener( + 'click', + ((web.Event _) { + if (inlineToc.getAttribute('data-expanded') == 'true') { + closeMenu(); + } else { + inlineToc.setAttribute('data-expanded', 'true'); + dropdownButton.ariaExpanded = 'true'; + } + }).toJS, + ); + + web.document.addEventListener( + 'keydown', + ((web.KeyboardEvent event) { + if (event.key == 'Escape') { + closeMenu(); + } + }).toJS, + ); + + // Close the dropdown if any link in the TOC is navigated to. + final inlineTocLinks = inlineToc.querySelectorAll('a'); + for (var i = 0; i < inlineTocLinks.length; i++) { + final tocLink = inlineTocLinks.item(i) as web.Element; + tocLink.addEventListener( + 'click', + ((web.Event _) { + closeMenu(); + }).toJS, + ); + } + + // Close the dropdown if anywhere not in the inline TOC is clicked. + web.document.addEventListener( + 'click', + ((web.Event event) { + if ((event.target as web.Element).closest('#toc-top') != null) { + return; + } + closeMenu(); + }).toJS, + ); +} + +void _setUpTocActiveObserver() { + final headings = web.document.querySelectorAll( + 'article .header-wrapper, #site-content-title', + ); + final currentHeaderText = web.document.getElementById('current-header'); + + // No need to have toc scrollspy if there is only one non-title heading. + if (headings.length < 2 || currentHeaderText == null) return; + + final visibleAnchors = {}; + final initialHeaderText = currentHeaderText.textContent; + + final observer = web.IntersectionObserver( + ((JSArray entries) { + for (var i = 0; i < entries.length; i++) { + final entry = entries[i]; + final headingId = entry.target.querySelector('h1, h2, h3')?.id; + if (headingId == null) return; + + if (entry.isIntersecting) { + visibleAnchors.add(headingId); + } else { + visibleAnchors.remove(headingId); + } + } + + if (visibleAnchors.isNotEmpty) { + var isFirst = true; + + // If the page title is visible, set the current header to its contents. + if (visibleAnchors.contains('document-title')) { + currentHeaderText.textContent = initialHeaderText; + isFirst = false; + } + + final tocLinks = web.document.querySelectorAll( + '.site-toc .sidenav-item a', + ); + for (var i = 0; i < tocLinks.length; i++) { + final tocLink = tocLinks.item(i) as web.Element; + final headingId = tocLink.getAttribute('href')?.substring(1); + if (headingId == null) continue; + + final sidenavItem = tocLink.closest('.sidenav-item'); + if (sidenavItem == null) continue; + + if (visibleAnchors.contains(headingId)) { + sidenavItem.classList.add('active'); + + if (isFirst) { + currentHeaderText.textContent = tocLink.textContent; + isFirst = false; + } + } else { + sidenavItem.classList.remove('active'); + } + } + } + }).toJS, + web.IntersectionObserverInit(rootMargin: '-80px 0px -25% 0px'), + ); + + for (var i = 0; i < headings.length; i++) { + observer.observe(headings.item(i) as web.Element); + } +} diff --git a/site/lib/src/components/common/breadcrumbs.dart b/site/lib/src/components/common/breadcrumbs.dart new file mode 100644 index 00000000000..39e0a4b861e --- /dev/null +++ b/site/lib/src/components/common/breadcrumbs.dart @@ -0,0 +1,171 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:collection/collection.dart'; +import 'package:jaspr/jaspr.dart'; +import 'package:jaspr_content/jaspr_content.dart'; + +import '../../util.dart'; +import 'material_icon.dart'; + +/// Breadcrumbs navigation component that +/// follows ARIA guidelines and includes RDFa markup. +/// +/// References: +/// - https://developers.google.com/search/docs/data-types/breadcrumb +/// - https://schema.org/BreadcrumbList +/// - https://www.w3.org/TR/wai-aria-practices/examples/breadcrumb/index.html +class PageBreadcrumbs extends StatelessComponent { + const PageBreadcrumbs({super.key}); + + @override + Component build(BuildContext context) { + final crumbs = _breadcrumbsForPage(context.pages, context.page); + if (crumbs == null || crumbs.isEmpty) { + return const Component.empty(); + } + + return nav( + classes: 'breadcrumbs', + attributes: {'aria-label': 'breadcrumb'}, + [ + ol( + classes: 'breadcrumb-list', + attributes: { + 'vocab': 'https://schema.org/', + 'typeof': 'BreadcrumbList', + }, + [ + for (var i = 0; i < crumbs.length; i++) + _BreadcrumbItemComponent( + crumb: crumbs[i], + index: i, + isLast: i == crumbs.length - 1, + ), + ], + ), + ], + ); + } + + /// Extract breadcrumbs from page data. + /// + /// Uses page metadata to generate breadcrumb titles with fallbacks: + /// `breadcrumb` > `shortTitle` > `title`. + List<_BreadcrumbItem>? _breadcrumbsForPage(List pages, Page page) { + final pageUrl = page.url; + + // Only show breadcrumbs if the URL isn't empty. + if (pageUrl.isEmpty || pageUrl == '/') return null; + + final pageBreadcrumb = page.breadcrumb; + if (pageBreadcrumb == null) { + return null; + } + + final segments = pageUrl + .split('/') + .where((s) => s.isNotEmpty) + .toList(growable: false); + if (segments.isEmpty) return null; + + final breadcrumbs = <_BreadcrumbItem>[]; + var currentPath = ''; + + // Build breadcrumbs for each segment except the current page. + for (var i = 0; i < segments.length - 1; i++) { + currentPath += '/${segments[i]}'; + + // Try to find the index page for this directory. + final indexPage = pages.firstWhereOrNull( + (p) => p.url == currentPath, + ); + + // Skip if no index page found. + if (indexPage == null) continue; + + if (indexPage.breadcrumb case final indexBreadcrumb?) { + breadcrumbs.add( + _BreadcrumbItem( + title: indexBreadcrumb, + url: indexPage.url, + ), + ); + } + } + + // If there are no parent breadcrumbs and this isn't a top-level doc, + // don't render the single one. + if (breadcrumbs.isEmpty && segments.length > 1) { + return null; + } + + // Add the current page as the final breadcrumb. + breadcrumbs.add( + _BreadcrumbItem( + title: pageBreadcrumb, + url: pageUrl, + ), + ); + + return breadcrumbs; + } +} + +extension on Page { + String? get breadcrumb { + final pageData = data.page; + + final breadcrumbString = + pageData['breadcrumb'] ?? pageData['shortTitle'] ?? pageData['title']; + if (breadcrumbString is! String || breadcrumbString.isEmpty) { + return null; + } + return breadcrumbString; + } +} + +final class _BreadcrumbItem { + const _BreadcrumbItem({required this.title, required this.url}); + + final String title; + final String url; +} + +/// An individual breadcrumb item that corresponds to one link. +final class _BreadcrumbItemComponent extends StatelessComponent { + const _BreadcrumbItemComponent({ + required this.crumb, + required this.index, + required this.isLast, + }); + + final _BreadcrumbItem crumb; + final int index; + final bool isLast; + + @override + Component build(BuildContext context) => li( + classes: [ + 'breadcrumb-item', + if (isLast) 'active', + ].toClasses, + attributes: { + 'property': 'itemListElement', + 'typeof': 'ListItem', + if (isLast) 'aria-current': 'page', + }, + [ + a( + href: crumb.url, + attributes: {'property': 'item', 'typeof': 'WebPage'}, + [ + span(attributes: {'property': 'name'}, [text(crumb.title)]), + ], + ), + meta(attributes: {'property': 'position', 'content': index.toString()}), + if (!isLast) const MaterialIcon('chevron_right'), + ], + ); +} diff --git a/site/lib/src/components/common/button.dart b/site/lib/src/components/common/button.dart new file mode 100644 index 00000000000..41eea870529 --- /dev/null +++ b/site/lib/src/components/common/button.dart @@ -0,0 +1,91 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import '../../util.dart'; +import 'material_icon.dart'; + +/// A generic button component with different style variants. +class Button extends StatelessComponent { + /// Creates a button with either textual [content], an [icon] ID, or both. + const Button({ + super.key, + this.icon, + this.href, + this.content, + this.style = ButtonStyle.text, + this.id, + this.attributes = const {}, + this.classes, + this.disabled = false, + this.title, + this.asRaw = false, + this.onClick, + }) : assert(content != null || icon != null); + + final String? content; + final String? title; + final ButtonStyle style; + final String? icon; + final String? id; + final String? href; + final Map attributes; + final bool disabled; + final bool asRaw; + final List? classes; + final void Function()? onClick; + + @override + Component build(BuildContext context) { + final mergedAttributes = { + ...attributes, + if (disabled) 'disabled': 'disabled', + 'title': ?title, + }; + + final mergedClasses = [ + style.cssClass, + if (icon != null && content == null) 'icon-button', + ...?classes, + ].toClasses; + + final children = [ + if (icon case final iconId?) MaterialIcon(iconId), + if (content case final contentText?) + asRaw ? raw(contentText) : text(contentText), + ]; + + if (href case final href?) { + return a( + id: id, + href: href, + classes: mergedClasses, + attributes: mergedAttributes, + onClick: onClick, + children, + ); + } else { + return button( + id: id, + classes: mergedClasses, + attributes: mergedAttributes, + onClick: onClick, + children, + ); + } + } +} + +enum ButtonStyle { + filled, + outlined, + text; + + String get cssClass => switch (this) { + ButtonStyle.filled => 'filled-button', + ButtonStyle.outlined => 'outlined-button', + ButtonStyle.text => 'text-button', + }; +} diff --git a/site/lib/src/components/common/card.dart b/site/lib/src/components/common/card.dart new file mode 100644 index 00000000000..91892ba1150 --- /dev/null +++ b/site/lib/src/components/common/card.dart @@ -0,0 +1,141 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import '../../util.dart'; + +class Card extends StatelessComponent { + /// Creates a card that can have a [header], [content], and [actions]. + /// + /// If the card should be collapsible, use [Card.expandable] instead. + const Card({ + super.key, + this.header = const [], + this.content = const [], + this.actions, + this.outlined = false, + this.filled = false, + this.id, + this.attributes = const {}, + this.additionalClasses, + this.link, + }) : collapsedContent = null, + expandable = false, + initiallyExpanded = true; + + /// Creates an expandable card, such as used on the glossary page. + const Card.expandable({ + super.key, + this.header = const [], + required List expandedContent, + required this.collapsedContent, + this.actions, + this.outlined = false, + this.filled = false, + required String this.id, + this.attributes = const {}, + this.additionalClasses, + this.initiallyExpanded = true, + }) : content = expandedContent, + link = null, + expandable = true; + + /// Creates a [Card] from a set of attributes parsed from markdown. + factory Card.fromAttributes( + Map attributes, + Component? child, + ) { + final link = attributes['link']; + final title = + attributes['title'] ?? + (throw Exception('Card component requires a "title" attribute.')); + final outlined = attributes['outlined'] == 'true'; + return Card( + header: [ + Component.element( + tag: 'header', + classes: 'card-title', + children: [text(title)], + ), + ], + content: [?child], + link: link, + filled: link != null, + outlined: outlined, + ); + } + + final List header; + final List content; + final List? collapsedContent; + final CardActions? actions; + + final bool outlined; + final bool filled; + final bool expandable; + final String? id; + final String? link; + final Map attributes; + final String? additionalClasses; + final bool initiallyExpanded; + + @override + Component build(BuildContext context) { + final classes = [ + 'card', + if (outlined) 'outlined-card', + if (filled) 'filled-card', + if (expandable) 'expandable-card', + ?additionalClasses, + ].toClasses; + + final children = [ + if (header.isNotEmpty) div(classes: 'card-header', header), + if (collapsedContent case final collapsedContent?) + div(classes: 'initial-content', collapsedContent), + div( + id: id != null ? '$id-content' : null, + classes: [ + 'card-content', + if (expandable) 'expandable-content', + ].toClasses, + content, + ), + ?actions, + ]; + + if (link case final link?) { + return a( + classes: classes, + id: id, + href: link, + attributes: attributes, + children, + ); + } else { + return div( + classes: classes, + id: id, + attributes: attributes, + children, + ); + } + } +} + +class CardActions extends StatelessComponent { + const CardActions({this.leading = const [], this.trailing = const []}); + + final List leading; + final List trailing; + + @override + Component build(BuildContext context) { + return div(classes: 'card-actions', [ + div(classes: 'leading', leading), + div(classes: 'trailing', trailing), + ]); + } +} diff --git a/site/lib/src/components/common/chip.dart b/site/lib/src/components/common/chip.dart new file mode 100644 index 00000000000..a9484dab171 --- /dev/null +++ b/site/lib/src/components/common/chip.dart @@ -0,0 +1,337 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:universal_web/web.dart' as web; + +import '../../util.dart'; +import '../util/global_event_listener.dart'; +import 'material_icon.dart'; + +/// A set of Material Design-like chips for configuration. +class ChipSet extends StatelessComponent { + const ChipSet(this.chips, {this.onReset}); + + final List chips; + final void Function()? onReset; + + @override + Component build(BuildContext context) => div(classes: 'chip-set', [ + ...chips, + if (onReset case final onReset?) + button( + id: 'reset-filters', + classes: 'text-button', + events: {'click': (_) => onReset()}, + [text('Clear filters')], + ), + ]); +} + +class InfoChip extends StatelessComponent { + const InfoChip({ + super.key, + required this.label, + this.icon, + this.iconPath, + this.iconSize = 18, + this.iconViewBox = '0 0 18 18', + this.title, + this.classes, + this.attributes, + }); + + final String label; + final String? icon; + final String? iconPath; + final int iconSize; + final String iconViewBox; + final String? title; + final List? classes; + final Map? attributes; + + @override + Component build(BuildContext context) { + final chipClasses = ['chip', 'info-chip', ...?classes]; + + return div( + classes: chipClasses.toClasses, + attributes: attributes, + [ + if (icon case final icon?) + MaterialIcon(icon, title: title, classes: ['chip-icon']) + else if (iconPath case final iconPath?) + svg( + classes: 'chip-icon', + width: iconSize.px, + height: iconSize.px, + viewBox: iconViewBox, + attributes: { + 'aria-hidden': 'true', + 'title': ?title, + }, + [ + Component.element(tag: 'path', attributes: {'d': iconPath}), + ], + ), + span(classes: 'label', [text(label)]), + ], + ); + } +} + +class FilterChip extends StatelessComponent { + const FilterChip({ + super.key, + required this.label, + this.icon, + this.iconPath, + this.iconSize = 18, + this.iconViewBox = '0 0 18 18', + this.ariaLabel, + this.showCheckIcon = true, + this.selected = false, + this.onTap, + }); + + final String label; + final String? icon; + final String? iconPath; + final int iconSize; + final String iconViewBox; + final String? ariaLabel; + final bool showCheckIcon; + final bool selected; + final void Function()? onTap; + + @override + Component build(BuildContext context) { + return button( + classes: ['chip', 'filter-chip', if (selected) 'selected'].toClasses, + attributes: { + 'role': 'checkbox', + 'aria-checked': selected ? 'true' : 'false', + 'aria-label': ?ariaLabel, + }, + events: {'click': (_) => onTap?.call()}, + [ + if (showCheckIcon) + svg( + classes: 'chip-icon leading-icon', + attributes: { + 'viewBox': iconViewBox, + 'aria-hidden': 'true', + }, + [ + const Component.element( + tag: 'path', + attributes: { + 'd': + 'M6.75012 12.1274L3.62262 8.99988L2.55762 10.0574L' + '6.75012 14.2499L15.7501 5.24988L14.6926 4.19238L' + '6.75012 12.1274Z', + }, + ), + ], + ) + else if (icon case final icon?) + MaterialIcon(icon, classes: ['chip-icon', 'leading-icon']) + else if (iconPath case final iconPath?) + svg( + classes: 'chip-icon leading-icon', + width: iconSize.px, + height: iconSize.px, + viewBox: iconViewBox, + attributes: {'aria-hidden': 'true'}, + [ + Component.element( + tag: 'path', + attributes: {'d': iconPath}, + ), + ], + ), + span(classes: 'label', [text(label)]), + ], + ); + } +} + +class SelectChip extends StatefulComponent { + const SelectChip({ + super.key, + required this.label, + required this.menuId, + this.menuItems = const [], + this.showDropdownIcon = true, + this.dropdownIconPath, + this.selectedValue, + this.onSelect, + }); + + final String label; + final String menuId; + final List> menuItems; + final bool showDropdownIcon; + final String? dropdownIconPath; + final T? selectedValue; + final void Function(T?)? onSelect; + + @override + State createState() => _SelectChipState(); +} + +class _SelectChipState extends State> { + bool isMenuShown = false; + + @override + void didUpdateComponent(SelectChip oldComponent) { + super.didUpdateComponent(oldComponent); + + if (oldComponent.selectedValue != component.selectedValue) { + setState(() { + isMenuShown = false; + }); + } + } + + @override + Component build(BuildContext context) { + return GlobalEventListener( + onClick: (event) { + // If not clicking inside a menu wrapper, close the menu. + if ((event.target as web.Element?)?.closest('.button-menu-wrapper') == + null) { + setState(() { + isMenuShown = false; + }); + } + }, + onKeyDown: (event) { + // If pressing the `esc` key in the menu wrapper, close the menu. + if (event.key == 'Escape' && + (event.target as web.Element?)?.closest('.button-menu-wrapper') != + null) { + setState(() { + isMenuShown = false; + }); + } + }, + div(classes: 'button-menu-wrapper', [ + button( + classes: [ + 'chip', + 'select-chip', + if (component.selectedValue != null) 'selected', + ].toClasses, + attributes: { + 'aria-controls': component.menuId, + 'aria-expanded': isMenuShown ? 'true' : 'false', + }, + events: { + 'click': (_) { + setState(() { + isMenuShown = !isMenuShown; + }); + }, + }, + [ + span(classes: 'label', [text(component.label)]), + if (component.showDropdownIcon) + svg( + classes: 'chip-icon trailing-icon', + width: 24.px, + height: 24.px, + viewBox: '0 0 24 24', + attributes: {'aria-hidden': 'true'}, + [ + Component.element( + tag: 'path', + attributes: { + 'd': component.dropdownIconPath ?? 'M7 10l5 5 5-5H7z', + }, + ), + ], + ), + ], + ), + if (component.menuItems.isNotEmpty) + div( + id: component.menuId, + classes: 'select-menu${isMenuShown ? ' show-menu' : ''}', + [ + ul( + attributes: {'role': 'listbox'}, + [ + for (final item in component.menuItems) + item._buildItem( + item.value == component.selectedValue, + () { + component.onSelect?.call( + item.value == component.selectedValue + ? null + : item.value, + ); + setState(() { + isMenuShown = false; + }); + }, + ), + ], + ), + ], + ), + ]), + ); + } +} + +class SelectMenuItem { + const SelectMenuItem({ + required this.label, + required this.value, + this.icon, + this.iconPath, + this.iconSize = 24, + this.iconViewBox = '0 0 24 24', + }); + + final String label; + final T value; + final String? icon; + final String? iconPath; + final int iconSize; + final String iconViewBox; + + Component _buildItem(bool isSelected, void Function()? onTap) { + return li([ + button( + classes: isSelected ? 'selected' : null, + attributes: { + 'role': 'option', + 'aria-selected': isSelected.toString(), + }, + events: {'click': (_) => onTap?.call()}, + [ + if (icon case final icon?) + MaterialIcon(icon) + else if (iconPath case final iconPath?) + svg( + classes: 'menu-icon', + width: iconSize.px, + height: iconSize.px, + viewBox: iconViewBox, + attributes: {'aria-hidden': 'true'}, + [ + Component.element( + tag: 'path', + attributes: {'d': iconPath}, + ), + ], + ), + span(classes: 'label', [text(label)]), + ], + ), + ]); + } +} diff --git a/site/lib/src/components/common/client/cookie_notice.dart b/site/lib/src/components/common/client/cookie_notice.dart new file mode 100644 index 00000000000..d04fbadc746 --- /dev/null +++ b/site/lib/src/components/common/client/cookie_notice.dart @@ -0,0 +1,86 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:universal_web/web.dart' as web; + +import '../../../util.dart'; +import '../button.dart'; + +/// The cookie banner to show on a user's first time visiting the site. +@client +final class CookieNotice extends StatefulComponent { + const CookieNotice({super.key}); + + @override + State createState() => _CookieNoticeState(); +} + +final class _CookieNoticeState extends State { + static const _cookieStorageKey = 'cookie-consent'; + + bool showNotice = false; + + @override + void initState() { + if (kIsWeb) { + var shouldShowNotice = true; + if (web.window.localStorage.getItem(_cookieStorageKey) + case final lastConsentedMs?) { + if (int.tryParse(lastConsentedMs) case final msFromEpoch?) { + final consentedDateTime = DateTime.fromMillisecondsSinceEpoch( + msFromEpoch, + ); + final difference = consentedDateTime.difference(DateTime.now()); + if (difference.inDays < 180) { + // If consented less than 180 days ago, don't show the notice. + shouldShowNotice = false; + } + } + } + + showNotice = shouldShowNotice; + } + super.initState(); + } + + @override + Component build(BuildContext context) { + return section( + id: 'cookie-notice', + classes: [if (showNotice) 'show'].toClasses, + attributes: {'data-nosnippet': 'true'}, + [ + div(classes: 'container', [ + p([ + text( + 'docs.flutter.dev uses cookies from Google to deliver and ' + 'enhance the quality of its services and to analyze traffic.', + ), + ]), + div(classes: 'button-group', [ + const Button( + content: 'Learn more', + href: 'https://policies.google.com/technologies/cookies', + attributes: {'target': '_blank', 'rel': 'noopener'}, + ), + Button( + content: 'OK, got it', + style: ButtonStyle.filled, + onClick: () { + web.window.localStorage.setItem( + _cookieStorageKey, + DateTime.now().millisecondsSinceEpoch.toString(), + ); + setState(() { + showNotice = false; + }); + }, + ), + ]), + ]), + ], + ); + } +} diff --git a/site/lib/src/components/common/client/copy_button.dart b/site/lib/src/components/common/client/copy_button.dart new file mode 100644 index 00000000000..8fdaf2d306f --- /dev/null +++ b/site/lib/src/components/common/client/copy_button.dart @@ -0,0 +1,72 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import 'package:universal_web/web.dart' as web; + +import '../button.dart'; + +@client +class CopyButton extends StatefulComponent { + const CopyButton({ + required this.toCopy, + this.buttonText, + this.classes = const [], + this.title, + }); + + final String toCopy; + final String? title; + final String? buttonText; + final List classes; + + @override + State createState() => _CopyButtonState(); +} + +class _CopyButtonState extends State { + bool _hidden = true; + bool _copied = false; + + @override + void initState() { + // Unhide the copy button if successfully initialized on the client. + if (kIsWeb && component.toCopy.isNotEmpty) { + _hidden = false; + } + + super.initState(); + } + + void _copy() { + web.window.navigator.clipboard.writeText(component.toCopy); + + setState(() => _copied = true); + + Future.delayed(const Duration(seconds: 2), () { + if (mounted) { + setState(() => _copied = false); + } + }); + } + + @override + Component build(BuildContext _) { + final iconButton = component.buttonText == null; + + return Button( + style: iconButton ? ButtonStyle.text : ButtonStyle.filled, + classes: [ + 'copy-button', + if (_hidden) 'hidden', + ...component.classes, + ], + title: component.title ?? 'Copy ${component.toCopy} to your clipboard.', + content: _copied ? 'Copied!' : component.buttonText, + icon: iconButton ? 'content_copy' : null, + onClick: _copy, + ); + } +} diff --git a/site/lib/src/components/common/client/download_latest_button.dart b/site/lib/src/components/common/client/download_latest_button.dart new file mode 100644 index 00000000000..25ba9fdfa6c --- /dev/null +++ b/site/lib/src/components/common/client/download_latest_button.dart @@ -0,0 +1,94 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:meta/meta.dart'; + +import '../../../models/flutter_release_model.dart'; + +@client +class DownloadLatestButton extends StatefulComponent { + const DownloadLatestButton({required this.os, this.arch, super.key}); + + /// Creates a [DownloadLatestButton] from a set of attributes parsed + /// from markdown. + factory DownloadLatestButton.fromAttributes(Map attributes) { + final os = + attributes['os'] ?? + (throw Exception( + 'DownloadLatestButton component requires an "os" attribute.', + )); + final arch = attributes['arch']; + return DownloadLatestButton( + os: os.toLowerCase(), + arch: arch?.toLowerCase(), + ); + } + + final String os; + final String? arch; + + @override + State createState() => _DownloadLatestButtonState(); +} + +class _DownloadLatestButtonState extends State { + @override + void initState() { + super.initState(); + + if (kIsWeb) { + loadLatestRelease(); + } + } + + bool isLoading = true; + String? error; + FlutterRelease? latestRelease; + + @awaitNotRequired + Future loadLatestRelease() async { + try { + final releasesData = await FlutterRelease.fetchFlutterReleases( + component.os, + ); + final filteredReleases = releasesData.where( + (release) { + return release.channel == 'stable' && + (component.arch == null || + release.architecture == component.arch); + }, + ); + + setState(() { + latestRelease = filteredReleases.firstOrNull; + isLoading = false; + }); + } catch (e) { + setState(() { + error = e.toString(); + isLoading = false; + }); + } + } + + @override + Component build(BuildContext context) { + if (!isLoading && error == null && latestRelease == null) { + return const Component.empty(); + } + return a( + href: latestRelease?.url ?? '#', + classes: 'filled-button', + [ + if (isLoading) + text('(loading...)') + else if (error != null) + text('(failed)') + else if (latestRelease case final latestRelease?) + text(latestRelease.url.split('/').last), + ], + ); + } +} diff --git a/site/lib/src/components/common/client/feedback.dart b/site/lib/src/components/common/client/feedback.dart new file mode 100644 index 00000000000..274cc4a25d6 --- /dev/null +++ b/site/lib/src/components/common/client/feedback.dart @@ -0,0 +1,90 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import '../../../analytics/analytics.dart'; +import '../button.dart'; + +/// Provides the user options to provide feedback on the specified page. +@client +final class FeedbackComponent extends StatefulComponent { + const FeedbackComponent({required this.issueUrl}); + + final String issueUrl; + + @override + State createState() => _FeedbackComponentState(); +} + +final class _FeedbackComponentState extends State { + _FeedbackState feedback = _FeedbackState.none; + + void _provideFeedback({required bool helpful}) { + if (!kIsWeb) return; + + setState( + () => feedback = helpful + ? _FeedbackState.helpful + : _FeedbackState.unhelpful, + ); + analytics.sendFeedback(helpful); + } + + @override + Component build(BuildContext context) { + return div(id: 'page-feedback', [ + div(classes: 'feedback', [ + div([Component.text(feedback.introduction)]), + ...switch (feedback) { + _FeedbackState.none => [ + div(classes: 'feedback-buttons', [ + Button( + icon: 'thumb_up', + title: 'Yes, this page was helpful.', + onClick: () => _provideFeedback(helpful: true), + ), + Button( + icon: 'thumb_down', + title: 'No, this page was not helpful or had an issue', + onClick: () => _provideFeedback(helpful: false), + ), + ]), + ], + _FeedbackState.helpful => [ + Button( + content: 'Provide details', + icon: 'feedback', + title: 'Provide detailed feedback.', + href: component.issueUrl, + attributes: const {'target': '_blank', 'rel': 'noopener'}, + ), + ], + _FeedbackState.unhelpful => [ + Button( + content: 'Provide details', + icon: 'bug_report', + title: 'Provide feedback or report an issue.', + href: component.issueUrl, + attributes: const {'target': '_blank', 'rel': 'noopener'}, + ), + ], + }, + ]), + ]); + } +} + +enum _FeedbackState { + none('Was this page\'s content helpful?'), + helpful('Thank you for your feedback!'), + unhelpful( + 'Thank you for your feedback! ' + 'Please let us know what we can do to improve.', + ); + + const _FeedbackState(this.introduction); + + final String introduction; +} diff --git a/site/lib/src/components/common/client/on_this_page_button.dart b/site/lib/src/components/common/client/on_this_page_button.dart new file mode 100644 index 00000000000..1d1a2b37ccf --- /dev/null +++ b/site/lib/src/components/common/client/on_this_page_button.dart @@ -0,0 +1,33 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:universal_web/web.dart' as web; + +import '../material_icon.dart'; + +/// Used in the table of contents to scroll to the top of the page. +@client +final class OnThisPageButton extends StatelessComponent { + const OnThisPageButton(); + + @override + Component build(BuildContext _) => header( + events: { + 'click': (_) { + final distanceBetweenTop = + web.document.documentElement?.scrollTop ?? + web.document.body?.scrollTop; + + if (distanceBetweenTop != null && distanceBetweenTop > 0) { + web.window.scrollTo(web.ScrollToOptions(behavior: 'smooth', top: 0)); + } + }, + }, + [ + const MaterialIcon('list'), + span([text('On this page')]), + ], + ); +} diff --git a/site/lib/src/components/common/client/os_selector.dart b/site/lib/src/components/common/client/os_selector.dart new file mode 100644 index 00000000000..24f5e3671f2 --- /dev/null +++ b/site/lib/src/components/common/client/os_selector.dart @@ -0,0 +1,94 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:universal_web/web.dart' as web; + +import '../../../util.dart'; + +@client +class OsSelector extends StatefulComponent { + const OsSelector({super.key}); + + @override + State createState() => _OsSelectorState(); +} + +class _OsSelectorState extends State { + // This value is currently not synced across potential multiple instances + // of the OS selector on the page. In practice, this currently does not + // happen, but would need to be addressed if changed. + OperatingSystem selectedOs = OperatingSystem.windows; + + @override + void initState() { + super.initState(); + + if (kIsWeb) { + final currentOs = getOS() ?? OperatingSystem.windows; + setOS(currentOs); + } + } + + void setOS(OperatingSystem os) { + setState(() { + selectedOs = os; + }); + + final selectedOsTextSpans = web.document.querySelectorAll( + '.selected-os-text', + ); + for (var i = 0; i < selectedOsTextSpans.length; i++) { + final span = selectedOsTextSpans.item(i) as web.Element; + span.textContent = os.label; + } + + final bodyClasses = web.document.body!.classList; + for (final os in OperatingSystem.values) { + bodyClasses.remove('show-${os.name}'); + } + bodyClasses.add('show-${os.name}'); + } + + @override + Component build(BuildContext context) { + return div(classes: 'card-grid narrow os-selector', [ + for (final os in OperatingSystem.values) + button( + id: 'install-${os.name}', + classes: [ + 'card outlined-card install-card', + if (selectedOs == os) 'selected-card', + ].toClasses, + attributes: { + 'data-os': os.name, + 'aria-label': 'Update docs to cover ${os.label}', + }, + events: { + 'click': (event) { + setOS(os); + }, + }, + [ + div(classes: 'card-leading', [ + img( + src: '/assets/images/docs/brand-svg/${os.name}.svg', + alt: '${os.label} logo', + attributes: { + 'width': '72', + 'height': '72', + 'aria-hidden': 'true', + }, + ), + ]), + div(classes: 'card-header text-center', [ + span(classes: 'card-title', [ + text(os.label), + ]), + ]), + ], + ), + ]); + } +} diff --git a/site/lib/src/components/common/dash_image.dart b/site/lib/src/components/common/dash_image.dart new file mode 100644 index 00000000000..0e008637ed1 --- /dev/null +++ b/site/lib/src/components/common/dash_image.dart @@ -0,0 +1,62 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:jaspr_content/jaspr_content.dart'; + +import '../../markdown/markdown_parser.dart'; + +class DashImage with CustomComponentBase { + const DashImage(); + + @override + Pattern get pattern => RegExp('DashImage', caseSensitive: false); + + @override + Component apply(_, Map attributes, _) { + final isFigure = attributes.containsKey('figure'); + final imgSrc = + attributes['image'] ?? + (throw Exception( + ' component requires an "image" attribute.', + )); + + final caption = attributes['caption'] ?? ''; + final alt = attributes['alt'] ?? caption; + + final figureClass = isFigure ? attributes['class'] : null; + final imgClass = attributes[isFigure ? 'img-class' : 'class']; + + final style = [ + if (attributes['img-style'] case final s?) s, + if (attributes['width'] case final w?) 'width: $w', + if (attributes['height'] case final h?) 'height: $h', + ].map((s) => s.trim()).map((s) => s.endsWith(';') ? s : '$s;').join(' '); + + final child = Component.fragment([ + img( + src: '/assets/images/docs/$imgSrc', + alt: alt, + classes: imgClass, + attributes: { + if (style.isNotEmpty) 'style': style, + }, + ), + if (caption.isNotEmpty) + figcaption(classes: 'figure-caption', [ + DashMarkdown(content: caption), + ]), + ]); + + if (isFigure) { + return figure(classes: figureClass, [ + div(classes: 'site-figure-container', [ + child, + ]), + ]); + } + + return child; + } +} diff --git a/site/lib/src/components/common/dropdown.dart b/site/lib/src/components/common/dropdown.dart new file mode 100644 index 00000000000..f5ade0574c7 --- /dev/null +++ b/site/lib/src/components/common/dropdown.dart @@ -0,0 +1,133 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import 'package:universal_web/web.dart' as web; + +import '../util/global_event_listener.dart'; + +/// The root component of a dropdown in a client component. +/// +/// Should include a [DropdownToggle] and [DropdownContent] +/// as children. +final class Dropdown extends StatefulComponent { + const Dropdown({required this.id, required this.children}); + + final String id; + final List children; + + @override + State createState() => _DropdownState(); +} + +final class _DropdownState extends State { + bool _expanded = false; + + void toggle({bool? to}) { + setState(() { + _expanded = to ?? !_expanded; + }); + } + + @override + Component build(BuildContext _) { + return GlobalEventListener( + onClick: (event) { + if (!_expanded) return; + final target = event.target as web.HTMLElement?; + if (target == null || target.closest('#${component.id}') == null) { + toggle(to: false); + } + }, + _DropdownRoot( + id: component.id, + expanded: _expanded, + toggle: toggle, + child: div( + id: component.id, + classes: 'dropdown', + attributes: {'data-expanded': _expanded.toString()}, + events: { + 'keydown': (e) { + final keydownEvent = e as web.KeyboardEvent; + if (_expanded && keydownEvent.key == 'Escape') { + toggle(to: false); + } + }, + 'focusout': (e) { + final relatedTarget = + (e as web.FocusEvent).relatedTarget as web.HTMLElement?; + if (relatedTarget != null && + relatedTarget.closest('#${component.id}') == null) { + toggle(to: false); + } + }, + }, + component.children, + ), + ), + ); + } +} + +final class DropdownToggle extends StatelessComponent { + const DropdownToggle(this.child); + + final Component child; + + @override + Component build(BuildContext context) { + final root = _DropdownRoot.of(context); + + return Component.wrapElement( + child: child, + classes: 'dropdown-button', + events: { + 'click': (e) { + root.toggle(); + }, + }, + attributes: { + 'aria-controls': root.contentId, + 'aria-expanded': root.expanded.toString(), + }, + ); + } +} + +final class DropdownContent extends StatelessComponent { + const DropdownContent(this.child); + + final Component child; + + @override + Component build(BuildContext context) => div( + id: _DropdownRoot.of(context).contentId, + classes: 'dropdown-content', + [child], + ); +} + +final class _DropdownRoot extends InheritedComponent { + const _DropdownRoot({ + required this.id, + required this.toggle, + this.expanded = false, + required super.child, + }); + + final String id; + final bool expanded; + final void Function({bool? to}) toggle; + + String get contentId => '$id-content'; + + @override + bool updateShouldNotify(_DropdownRoot oldRoot) => + expanded != oldRoot.expanded; + + static _DropdownRoot of(BuildContext context) => + context.dependOnInheritedComponentOfExactType<_DropdownRoot>()!; +} diff --git a/site/lib/src/components/common/fragment_target.dart b/site/lib/src/components/common/fragment_target.dart new file mode 100644 index 00000000000..f637b70ce6b --- /dev/null +++ b/site/lib/src/components/common/fragment_target.dart @@ -0,0 +1,22 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +/// An empty anchor that can act as a fragment target. +/// +/// Often useful when a header, or at least its ID, needs to be updated. +final class FragmentTarget extends StatelessComponent { + const FragmentTarget(this.id); + + final String id; + + @override + Component build(BuildContext context) => a( + href: '', + id: id, + attributes: {'aria-hidden': 'true'}, + [], + ); +} diff --git a/site/lib/src/components/common/material_icon.dart b/site/lib/src/components/common/material_icon.dart new file mode 100644 index 00000000000..c9a87f50bc5 --- /dev/null +++ b/site/lib/src/components/common/material_icon.dart @@ -0,0 +1,38 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import '../../util.dart'; + +/// A Material Symbols icon rendered as a span element. +class MaterialIcon extends StatelessComponent { + const MaterialIcon( + this.id, { + this.title, + this.label, + this.classes = const [], + }); + + final String id; + final List classes; + final String? title; + final String? label; + + @override + Component build(BuildContext _) { + return span( + classes: ['material-symbols', ...classes].toClasses, + attributes: { + 'title': ?title, + if (label ?? title case final labelToUse?) + 'aria-label': labelToUse + else + 'aria-hidden': 'true', + 'translate': 'no', + }, + [text(id)], + ); + } +} diff --git a/site/lib/src/components/common/prev_next.dart b/site/lib/src/components/common/prev_next.dart new file mode 100644 index 00000000000..3f207450bcf --- /dev/null +++ b/site/lib/src/components/common/prev_next.dart @@ -0,0 +1,57 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import 'material_icon.dart'; + +/// Previous and next page buttons to display at the end of a page +/// in a connected series of pages, such as the language docs. +class PrevNext extends StatelessComponent { + const PrevNext({super.key, this.previousPage, this.nextPage}); + + final ({String url, String title})? previousPage; + final ({String url, String title})? nextPage; + + @override + Component build(BuildContext context) { + if (previousPage == null && nextPage == null) { + return const Component.empty(); + } + + return nav(id: 'site-prev-next', [ + if (previousPage case final previousPage?) + _PrevNextCard(page: previousPage, isPrevious: true), + if (nextPage case final nextPage?) + _PrevNextCard(page: nextPage, isPrevious: false), + ]); + } +} + +class _PrevNextCard extends StatelessComponent { + const _PrevNextCard({required this.page, required this.isPrevious}); + + final ({String url, String title}) page; + final bool isPrevious; + + @override + Component build(BuildContext context) { + final classes = isPrevious ? 'prev' : 'next'; + final subtitle = isPrevious ? 'Previous' : 'Next'; + final ariaLabel = isPrevious ? 'Previous page: ' : 'Next page: '; + + return a(classes: classes, href: page.url, [ + if (isPrevious) const MaterialIcon('chevron_left'), + div([ + span( + classes: 'prev-next-subtitle', + attributes: {'aria-label': ariaLabel}, + [text(subtitle)], + ), + span(classes: 'prev-next-title', [text(page.title)]), + ]), + if (!isPrevious) const MaterialIcon('chevron_right'), + ]); + } +} diff --git a/site/lib/src/components/common/search.dart b/site/lib/src/components/common/search.dart new file mode 100644 index 00000000000..dddc8b83a57 --- /dev/null +++ b/site/lib/src/components/common/search.dart @@ -0,0 +1,38 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import 'material_icon.dart'; + +/// A search bar component, such as used on the glossary page. +class SearchBar extends StatelessComponent { + const SearchBar({ + required this.placeholder, + required this.label, + this.value, + this.onInput, + }); + + final String placeholder; + final String label; + final String? value; + final void Function(String)? onInput; + + @override + Component build(BuildContext context) => div(classes: 'search-row', [ + div(classes: 'search-wrapper', [ + const MaterialIcon('search', classes: ['leading-icon']), + input( + type: InputType.search, + value: value, + attributes: { + 'placeholder': placeholder, + 'aria-label': label, + }, + onInput: onInput != null ? (value) => onInput!(value as String) : null, + ), + ]), + ]); +} diff --git a/site/lib/src/components/common/tabs.dart b/site/lib/src/components/common/tabs.dart new file mode 100644 index 00000000000..026eca8676f --- /dev/null +++ b/site/lib/src/components/common/tabs.dart @@ -0,0 +1,146 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:jaspr_content/jaspr_content.dart'; + +import '../../util.dart'; + +/// A tabs component where children tabs can be switched between by the user. +class DashTabs implements CustomComponent { + static int _currentTabWrapperId = 0; + static int _currentTabId = 0; + + const DashTabs(); + + @override + Component? create(Node node, NodesBuilder builder) { + if (node is! ElementNode || node.tag != 'Tabs') { + return null; + } + + final tabs = node.children + ?.whereType() + .where((n) => n.tag == 'Tab') + .toList(growable: false); + if (tabs == null || tabs.length < 2) { + print('[ERROR] The element requires at least 2 children!'); + return null; + } + + final wrapperId = '${_currentTabWrapperId++}'; + + return _DashTabsWrapper( + id: wrapperId, + saveKey: node.attributes['key'], + wrapped: node.attributes['wrapped'] == 'true', + tabs: [ + for (final (tabIndex, tab) in tabs.indexed) + _DashTabPane( + tabName: tab.attributes['name']!, + baseId: '${_currentTabId++}', + isActive: tabIndex == 0, + wrapperId: wrapperId, + child: builder.build(tab.children), + saveId: tab.attributes['id'], + ), + ], + ); + } +} + +class _DashTabsWrapper extends StatelessComponent { + const _DashTabsWrapper({ + required this.id, + required this.tabs, + this.saveKey, + this.wrapped = false, + }); + + final String id; + final String? saveKey; + final bool wrapped; + final List<_DashTabPane> tabs; + + @override + Component build(BuildContext context) { + return div( + id: id, + classes: ['tabs-wrapper', if (wrapped) 'wrapped'].toClasses, + attributes: { + 'data-tab-save-key': ?saveKey, + }, + [ + ul( + classes: 'nav-tabs', + attributes: { + 'role': 'tablist', + }, + [ + for (final tab in tabs) + li(classes: 'nav-item', [ + a( + id: tab.tabId, + href: '#${tab.panelId}', + classes: [ + 'nav-link', + if (tab.isActive) 'active', + ].toClasses, + attributes: { + 'tabindex': '0', + 'data-tab-save-id': tab.saveId, + 'role': 'tab', + 'aria-controls': tab.panelId, + 'aria-selected': '${tab.isActive}', + }, + [text(tab.tabName)], + ), + ]), + ], + ), + div( + classes: 'tab-content', + tabs, + ), + ], + ); + } +} + +/// An individual pane in a collection of tabs. +class _DashTabPane extends StatelessComponent { + _DashTabPane({ + required this.tabName, + required String baseId, + required this.isActive, + required this.wrapperId, + required this.child, + String? saveId, + }) : tabId = '$baseId-tab', + panelId = '$baseId-tab-panel', + saveId = saveId ?? slugify(tabName); + + final String tabName; + final String tabId; + final String panelId; + final String saveId; + final bool isActive; + final String wrapperId; + final Component child; + + @override + Component build(BuildContext context) { + return div( + id: panelId, + classes: ['tab-pane', if (isActive) 'active'].toClasses, + attributes: { + 'role': 'tabpanel', + 'aria-labelledby': tabId, + 'data-tab-id': tabId, + 'data-tab-wrapper-id': wrapperId, + }, + [child], + ); + } +} diff --git a/site/lib/src/components/common/tags.dart b/site/lib/src/components/common/tags.dart new file mode 100644 index 00000000000..14c9f499540 --- /dev/null +++ b/site/lib/src/components/common/tags.dart @@ -0,0 +1,47 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import 'material_icon.dart'; + +/// A display of multiple categorical or descriptive tags. +class Tags extends StatelessComponent { + const Tags(this.tags); + + final List tags; + + @override + Component build(BuildContext context) => + div(classes: 'tags', [for (final tag in tags) tag]); +} + +/// An individual tag to categorize an item, +/// such as the type of an individual lint. +/// +/// Generally displayed within a [Tags] component. +class Tag extends StatelessComponent { + const Tag(this.content, {this.icon, this.title, this.label, this.color}); + + final String content; + final String? icon; + final String? title; + final String? label; + final String? color; + + @override + Component build(BuildContext context) { + return div( + classes: 'tag-label', + attributes: { + 'title': ?title, + 'aria-label': ?(label ?? title), + }, + [ + if (icon case final iconId?) MaterialIcon(iconId), + span([text(content)]), + ], + ); + } +} diff --git a/site/lib/src/components/common/wrapped_code_block.dart b/site/lib/src/components/common/wrapped_code_block.dart new file mode 100644 index 00000000000..1ed927706e0 --- /dev/null +++ b/site/lib/src/components/common/wrapped_code_block.dart @@ -0,0 +1,152 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; + +import '../../util.dart'; +import 'client/copy_button.dart'; + +/// A rendered code block with support for syntax highlighting, +/// line highlighting, filenames, language specifying, +/// line numbers, and more. +final class WrappedCodeBlock extends StatelessComponent { + const WrappedCodeBlock({ + super.key, + required this.content, + required this.language, + this.title, + this.highlightLines = const {}, + this.addedLines = const {}, + this.removedLines = const {}, + this.languagesToHide = const {'plaintext', 'console'}, + this.tag, + this.initialLineNumber = 1, + this.showLineNumbers = false, + this.textToCopy, + }); + + final List> content; + final String? textToCopy; + + final String language; + final String? title; + + final Set highlightLines; + final Set addedLines; + final Set removedLines; + final Set languagesToHide; + final CodeBlockTag? tag; + final int initialLineNumber; + + final bool showLineNumbers; + + @override + Component build(BuildContext context) { + return div( + classes: 'code-block-wrapper language-$language', + [ + if (title case final title?) + div( + classes: 'code-block-header', + [text(title)], + ), + div( + classes: [ + 'code-block-body', + if (tag case final codeTag?) ...['has-tag', codeTag.parentClass], + ].toClasses, + [ + if (tag case final codeTag?) + span( + classes: 'code-block-tag', + [text(codeTag.spanContent)], + ), + if (!languagesToHide.contains(language)) + span( + classes: 'code-block-language', + attributes: {'title': 'Language $language'}, + [text(language)], + ), + pre( + classes: [ + if (showLineNumbers) 'show-line-numbers', + 'opal', + ].toClasses, + attributes: {'tabindex': '0'}, + [ + code( + [ + for ( + var lineIndex = 0; + lineIndex < content.length; + lineIndex += 1 + ) + span( + classes: [ + 'line', + if (highlightLines.contains(lineIndex + 1)) + 'highlighted-line', + if (removedLines.contains(lineIndex + 1)) + 'removed-line', + if (addedLines.contains(lineIndex + 1)) 'added-line', + ].toClasses, + attributes: { + if (showLineNumbers) + 'data-line': '${initialLineNumber + lineIndex}', + }, + [ + switch (content[lineIndex]) { + // Add a zero-width space when empty + // so that the line isn't collapsed to 0 height. + final line when line.isEmpty => span( + styles: const Styles( + userSelect: UserSelect.none, + ), + [text('\u200b')], + ), + final lineSpans => span(lineSpans), + }, + text('\n'), + ], + ), + ], + ), + ], + ), + if (textToCopy case final textToCopy?) + CopyButton( + toCopy: textToCopy, + title: 'Copy code to clipboard', + ), + ], + ), + ], + ); + } +} + +/// A tag that can be applied to a code block. +enum CodeBlockTag { + good('good', parentClass: 'tag-good'), + bad('bad', parentClass: 'tag-bad'), + passesStaticAnalysis('static analysis: success', parentClass: 'passes-sa'), + failsStaticAnalysis('static analysis: failure', parentClass: 'fails-sa'), + runtimeSuccess('runtime: success', parentClass: 'runtime-success'), + runtimeFailure('runtime: failure', parentClass: 'runtime-fail'); + + const CodeBlockTag(this.spanContent, {required this.parentClass}); + + final String spanContent; + final String parentClass; + + static CodeBlockTag parse(String tag) => switch (tag) { + 'good' => good, + 'bad' => bad, + 'passes-sa' => passesStaticAnalysis, + 'fails-sa' => failsStaticAnalysis, + 'runtime-success' => runtimeSuccess, + 'runtime-fail' => runtimeFailure, + _ => throw ArgumentError('Unknown tag for code blocks: $tag'), + }; +} diff --git a/site/lib/src/components/common/youtube_embed.dart b/site/lib/src/components/common/youtube_embed.dart new file mode 100644 index 00000000000..0238f248f54 --- /dev/null +++ b/site/lib/src/components/common/youtube_embed.dart @@ -0,0 +1,72 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:jaspr_content/jaspr_content.dart'; + +import '../../util.dart'; + +class YoutubeEmbed with CustomComponentBase { + const YoutubeEmbed(); + + @override + Pattern get pattern => RegExp('YouTubeEmbed', caseSensitive: false); + + @override + Component apply( + String name, + Map attributes, + Component? child, + ) { + final rawVideoId = + attributes['id'] ?? + (throw Exception('YouTubeEmbed component requires an "id" attribute.')); + final videoTitle = + attributes['title'] ?? + (throw Exception( + 'YouTubeEmbed component requires a "title" attribute.', + )); + final fullWidth = attributes.containsKey('fullwidth'); + final playlistId = attributes['playlist']; + + final String videoId; + final int startTime; + if (rawVideoId.contains('?')) { + final idAndStartTime = rawVideoId.split('?'); + videoId = idAndStartTime[0]; + + final rawStartTime = idAndStartTime[1].split('start=')[1]; + startTime = int.tryParse(rawStartTime) ?? 0; + } else { + startTime = 0; + videoId = rawVideoId; + } + + // Instead of directly including a YouTube embed iframe, + // we use https://github.com/justinribeiro/lite-youtube which + // lazily loads the video, significantly reduces page load times, + // and enables configurability through element attributes. + return Component.element( + tag: 'lite-youtube', + attributes: { + 'videoid': videoId, + 'videotitle': videoTitle, + 'videoStartAt': '$startTime', + 'playlistid': ?playlistId, + }, + classes: [if (fullWidth) 'full-width'].toClasses, + children: [ + a( + classes: 'lite-youtube-fallback', + href: 'https://www.youtube.com/watch/$videoId', + target: Target.blank, + attributes: {'rel': 'noopener'}, + [ + text('Watch on YouTube in a new tab: "$videoTitle"'), + ], + ), + ], + ); + } +} diff --git a/site/lib/src/components/dartpad/dartpad_injector.dart b/site/lib/src/components/dartpad/dartpad_injector.dart new file mode 100644 index 00000000000..f9545c4dae2 --- /dev/null +++ b/site/lib/src/components/dartpad/dartpad_injector.dart @@ -0,0 +1,120 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'embedded_dartpad.dart'; + +import 'extract_content.dart' if (dart.library.io) 'extract_content_vm.dart'; + +/// Prepares a code block that will be replaced with an embedded +/// DartPad when the site is loaded. +final class DartPadWrapper extends StatefulComponent { + DartPadWrapper({ + super.key, + required this.content, + required this.title, + this.theme, + this.height, + this.runAutomatically = false, + }); + + final String content; + final String title; + final String? theme; + final String? height; + final bool runAutomatically; + + @override + State createState() => _DartPadWrapperState(); +} + +final class _DartPadWrapperState extends State { + @override + Component build(BuildContext context) { + return DartPadInjector( + title: component.title, + theme: component.theme, + height: component.height, + runAutomatically: component.runAutomatically, + // We don't pass the content here, so it's not part of the client + // component data. It will be retrieved by DartPadInjector automatically. + ); + } +} + +@client +class DartPadInjector extends StatefulComponent { + const DartPadInjector({ + required this.title, + this.theme, + this.height, + this.runAutomatically = false, + super.key, + }); + + final String title; + final String? theme; + final String? height; + final bool runAutomatically; + + @override + State createState() => _DartPadInjectorState(); +} + +class _DartPadInjectorState extends State { + static int _injectedIndex = 0; + + final String _frameId = () { + final nextId = _injectedIndex; + _injectedIndex += 1; + return 'embedded-dartpad-$nextId'; + }(); + + String content = ''; + + @override + void initState() { + super.initState(); + + if (kIsWeb) { + // During hydration, extract the content from the pre-rendered code block. + content = extractContent(context as Element); + } + } + + @override + Component build(BuildContext context) { + if (!kIsWeb) { + // During pre-rendering, get the content from the nearest DartPadWrapper. + final content = context + .findAncestorStateOfType<_DartPadWrapperState>() + ?.component + .content; + return pre([ + code( + attributes: {'title': component.title}, + [text(content ?? '')], + ), + ]); + } + + return Component.wrapElement( + attributes: { + 'height': ?component.height, + 'title': component.title, + }, + child: EmbeddedDartPad.create( + iframeId: _frameId, + theme: switch (component.theme) { + 'auto' => DartPadTheme.auto, + 'dark' => DartPadTheme.dark, + _ => DartPadTheme.light, + }, + embedLayout: true, + runAutomatically: component.runAutomatically, + code: content, + ), + ); + } +} diff --git a/site/lib/src/components/dartpad/embedded_dartpad.dart b/site/lib/src/components/dartpad/embedded_dartpad.dart new file mode 100644 index 00000000000..9a1bbf26c7a --- /dev/null +++ b/site/lib/src/components/dartpad/embedded_dartpad.dart @@ -0,0 +1,206 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:jaspr/jaspr.dart'; +import 'package:universal_web/js_interop.dart'; +import 'package:universal_web/web.dart' as web; + +/// An iframe-embedded DartPad that can be injected into a web page, +/// then have its source code updated. +final class EmbeddedDartPad extends StatefulComponent { + /// The unique identifier that's used to identify the created DartPad iframe. + /// + /// This ID is used both as the HTML element `id` and + /// as the iframe's `name` attribute for message targeting. + final String iframeId; + + /// The full URL of the DartPad iframe including + /// all path segments and query parameters. + final String _iframeUrl; + + /// The Dart source code to be displayed in the embedded DartPad's editor. + /// + /// The [code] should generally be valid Dart code for + /// the latest stable versions of Dart and Flutter. + final String code; + + /// Creates an embedded DartPad instance with + /// the specified [iframeId] and [iframeUrl]. + EmbeddedDartPad._({ + required this.iframeId, + required String iframeUrl, + required this.code, + }) : _iframeUrl = iframeUrl; + + /// Creates a new embedded DartPad element with the specified configuration. + /// + /// The [iframeId] is used to identify the created DartPad iframe. + /// It must be unique within the document and a valid HTML element ID. + /// + /// The [scheme] and [host] are used to construct the DartPad iframe URL. + /// [scheme] defaults to 'https' and [host] defaults to 'dartpad.dev'. + /// + /// To control the appearance of the embedded DartPad, + /// you can switch to the [embedLayout] and choose a specific [theme]. + /// + /// The [code] is the Dart source code to be injected into the DartPad editor + /// after it has finished loading. + factory EmbeddedDartPad.create({ + required String iframeId, + String? scheme, + String? host, + bool? embedLayout, + bool runAutomatically = false, + DartPadTheme? theme = DartPadTheme.auto, + required String code, + }) { + final dartPadUrl = Uri( + scheme: scheme ?? 'https', + host: host ?? 'dartpad.dev', + queryParameters: { + if (embedLayout ?? true) 'embed': '$embedLayout', + if (theme != DartPadTheme.auto) 'theme': '$theme', + if (runAutomatically) 'run': 'true', + }, + ).toString(); + + return EmbeddedDartPad._( + iframeId: iframeId, + iframeUrl: dartPadUrl, + code: code, + ); + } + + @override + State createState() => _EmbeddedDartPadState(); +} + +class _EmbeddedDartPadState extends State { + final GlobalNodeKey _iframeKey = GlobalNodeKey(); + bool _initialized = false; + + @override + void initState() { + super.initState(); + if (kIsWeb) { + // Start listening for the 'ready' message from the embedded DartPad. + late final JSExportedDartFunction readyHandler; + readyHandler = (web.MessageEvent event) { + if (event.data case _EmbedReadyMessage(type: 'ready', :final sender?)) { + // Verify the message is sent from the corresponding iframe, in case + // there are multiple DartPads being embedded at the same time. + if (sender != component.iframeId) { + return; + } + + web.window.removeEventListener('message', readyHandler); + if (_initialized) return; + _initialized = true; + _updateCode(); + } + }.toJS; + + web.window.addEventListener('message', readyHandler); + } + } + + @override + void didUpdateComponent(covariant EmbeddedDartPad oldComponent) { + super.didUpdateComponent(oldComponent); + + if (oldComponent.iframeId != component.iframeId) { + throw StateError( + 'The iframeId of an EmbeddedDartPad cannot be changed after creation.', + ); + } + if (oldComponent._iframeUrl != component._iframeUrl) { + throw StateError( + 'The iframeUrl of an EmbeddedDartPad cannot be changed after creation.', + ); + } + + if (oldComponent.code != component.code && _initialized) { + _updateCode(); + } + } + + /// Updates the source code displayed in the embedded DartPad's editor + /// with the specified Dart [code]. + void _updateCode() { + assert(_initialized, 'Cannot update code before iframe is initialized.'); + assert(_iframeKey.currentNode != null, 'Iframe element is not available.'); + + _iframeKey.currentNode!.contentWindowCrossOrigin?.postMessage( + _MessageToDartPad.updateSource(component.code), + _anyTargetOrigin, + ); + } + + @override + Component build(BuildContext context) { + return iframe( + key: _iframeKey, + id: component.iframeId, + name: component.iframeId, + src: component._iframeUrl, + loading: MediaLoading.lazy, + allow: 'clipboard-write', + [], + ); + } +} + +/// The themes available for an embedded DartPad instance. +enum DartPadTheme { + /// Light theme with a bright background. + light, + + /// Dark theme with a dark background. + dark, + + /// Theme that relies on DartPad's built-in theme handling. + auto, +} + +/// The target origin to be used for cross-frame messages sent to +/// the DartPad iframe's content window. +/// +/// Uses '*' to enable communication with DartPad instances +/// regardless of their actual origin. +final JSString _anyTargetOrigin = '*'.toJS; + +/// Represents a ready message received from the DartPad iframe. +/// +/// Sent by DartPad when it has finished loading and is ready to +/// receive code updates by sending it a cross-frame message. +extension type _EmbedReadyMessage._(JSObject _) { + /// The message type, which should be 'ready' for initialization messages. + external String? get type; + + /// The sender ID to identify which DartPad instance sent the message. + external String? get sender; +} + +/// Represents DartPad's expected format for receiving cross-frame messages +/// from its parent window, usually the [EmbeddedDartPad] host. +@anonymous +extension type _MessageToDartPad._(JSObject _) implements JSObject { + /// Creates a JavaScript object with the expected structure for + /// updating the source code in an embedded DartPad's editor. + external factory _MessageToDartPad._updateSource({ + required String sourceCode, + String type, + }); + + /// Creates a message to update that can be sent to + /// update the source code in an embedded DartPad instance. + /// + /// The [sourceCode] should generally be valid Dart code for + /// the latest stable versions of Dart and Flutter. + factory _MessageToDartPad.updateSource(String sourceCode) => + _MessageToDartPad._updateSource( + sourceCode: sourceCode, + type: 'sourceCode', + ); +} diff --git a/site/lib/src/components/dartpad/extract_content.dart b/site/lib/src/components/dartpad/extract_content.dart new file mode 100644 index 00000000000..433eab54e30 --- /dev/null +++ b/site/lib/src/components/dartpad/extract_content.dart @@ -0,0 +1,25 @@ +// Copyright 2025 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:js_interop'; + +import 'package:jaspr/browser.dart'; +import 'package:universal_web/web.dart' as web; + +/// Extracts the content of a
 block inside the given
+/// [element] during hydration.
+String extractContent(Element element) {
+  final r = element.parentRenderObjectElement?.renderObject as DomRenderObject?;
+  if (r == null) return '';
+
+  final code = r.retakeNode((node) {
+    return node.instanceOfString('Element') &&
+        (node as web.Element).tagName.toLowerCase() == 'pre';
+  });
+
+  if (code == null) return '';
+
+  code.parentNode?.removeChild(code);
+  return (code as web.Element).textContent ?? '';
+}
diff --git a/site/lib/src/components/dartpad/extract_content_vm.dart b/site/lib/src/components/dartpad/extract_content_vm.dart
new file mode 100644
index 00000000000..80b59939c22
--- /dev/null
+++ b/site/lib/src/components/dartpad/extract_content_vm.dart
@@ -0,0 +1,8 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+
+// Stub for non-web platforms.
+String extractContent(BuildContext context) => '';
diff --git a/site/lib/src/components/layout/banner.dart b/site/lib/src/components/layout/banner.dart
new file mode 100644
index 00000000000..6e5f0797705
--- /dev/null
+++ b/site/lib/src/components/layout/banner.dart
@@ -0,0 +1,61 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+
+/// The information to display in the site banner,
+/// as configured in the `src/data/banner.yml` file.
+@immutable
+final class BannerContent {
+  final String text;
+  final String linkText;
+  final String linkUri;
+  final bool newTab;
+
+  const BannerContent({
+    required this.text,
+    required this.linkText,
+    required this.linkUri,
+    this.newTab = false,
+  });
+
+  factory BannerContent.fromMap(Map bannerData) {
+    final text = bannerData['text'] as String;
+    final link = bannerData['link'] as Map;
+    final linkText = link['text'] as String;
+    final linkUri = link['url'] as String;
+    final newTab = link['newTab'] as bool? ?? false;
+
+    return BannerContent(
+      text: text,
+      linkText: linkText,
+      linkUri: linkUri,
+      newTab: newTab,
+    );
+  }
+}
+
+/// The site-wide banner.
+class DashBanner extends StatelessComponent {
+  const DashBanner(this.content, {super.key});
+
+  final BannerContent content;
+
+  @override
+  Component build(BuildContext context) => div(
+    id: 'site-banner',
+    attributes: {'role': 'alert'},
+    [
+      p([
+        text(content.text),
+        text(' '),
+        a(
+          href: content.linkUri,
+          target: content.newTab ? Target.blank : null,
+          [text(content.linkText)],
+        ),
+      ]),
+    ],
+  );
+}
diff --git a/site/lib/src/components/layout/footer.dart b/site/lib/src/components/layout/footer.dart
new file mode 100644
index 00000000000..a72a77bcd7c
--- /dev/null
+++ b/site/lib/src/components/layout/footer.dart
@@ -0,0 +1,187 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+
+/// The site-wide footer.
+final class DashFooter extends StatelessComponent {
+  const DashFooter({super.key});
+
+  @override
+  Component build(BuildContext context) {
+    return footer(
+      id: 'site-footer',
+      attributes: {'data-nosnippet': 'true'},
+      [
+        div(classes: 'footer-section footer-main', [
+          a(
+            href: '/',
+            classes: 'brand',
+            attributes: {'title': 'Flutter'},
+            [
+              img(
+                src:
+                    '/assets/images/branding/flutter/logo+text/horizontal/white.svg',
+                alt: 'Flutter logo',
+                width: 164,
+              ),
+            ],
+          ),
+          div(classes: 'footer-social-links', [
+            a(
+              href: 'https://blog.flutter.dev',
+              target: Target.blank,
+              attributes: {
+                'rel': 'noopener',
+                'title': 'Flutter\'s blog',
+              },
+              [
+                svg([
+                  const Component.element(
+                    tag: 'use',
+                    attributes: {
+                      'href': '/assets/images/social/medium.svg#medium',
+                    },
+                  ),
+                ]),
+              ],
+            ),
+            a(
+              href: 'https://youtube.com/@flutterdev',
+              target: Target.blank,
+              attributes: {
+                'rel': 'noopener',
+                'title': 'Flutter\'s YouTube channel',
+              },
+              [
+                svg([
+                  const Component.element(
+                    tag: 'use',
+                    attributes: {
+                      'href': '/assets/images/social/youtube.svg#youtube',
+                    },
+                  ),
+                ]),
+              ],
+            ),
+            a(
+              href: 'https://github.com/flutter',
+              target: Target.blank,
+              attributes: {
+                'rel': 'noopener',
+                'title': 'Flutter\'s GitHub organization',
+              },
+              [
+                svg([
+                  const Component.element(
+                    tag: 'use',
+                    attributes: {
+                      'href': '/assets/images/social/github.svg#github',
+                    },
+                  ),
+                ]),
+              ],
+            ),
+            a(
+              href: 'https://bsky.app/profile/flutter.dev',
+              target: Target.blank,
+              attributes: {
+                'rel': 'noopener',
+                'title': 'Flutter\'s Bluesky profile',
+              },
+              [
+                svg([
+                  const Component.element(
+                    tag: 'use',
+                    attributes: {
+                      'href': '/assets/images/social/bluesky.svg#bluesky',
+                    },
+                  ),
+                ]),
+              ],
+            ),
+            a(
+              href: 'https://twitter.com/FlutterDev',
+              target: Target.blank,
+              attributes: {
+                'rel': 'noopener',
+                'title': 'Flutter\'s X (Twitter) profile',
+              },
+              [
+                svg([
+                  const Component.element(
+                    tag: 'use',
+                    attributes: {'href': '/assets/images/social/x.svg#x'},
+                  ),
+                ]),
+              ],
+            ),
+          ]),
+        ]),
+        div(classes: 'footer-section footer-tray', [
+          div(classes: 'footer-licenses', [
+            text('Except as otherwise noted, this site is licensed under a '),
+            a(href: 'https://creativecommons.org/licenses/by/4.0/', [
+              text('Creative Commons Attribution 4.0 International License,'),
+            ]),
+            text(' and code samples are licensed under the '),
+            a(href: 'https://opensource.org/licenses/BSD-3-Clause', [
+              text('3-Clause BSD License.'),
+            ]),
+          ]),
+          div(classes: 'footer-utility-links', [
+            ul([
+              li([
+                a(
+                  href: '/tos',
+                  attributes: {'title': 'Terms of use'},
+                  [text('Terms')],
+                ),
+              ]),
+              li([
+                a(
+                  href: '/brand',
+                  attributes: {'title': 'Brand usage guidelines'},
+                  [text('Brand')],
+                ),
+              ]),
+              li([
+                a(
+                  href: 'https://policies.google.com/privacy',
+                  target: Target.blank,
+                  attributes: {'rel': 'noopener', 'title': 'Privacy policy'},
+                  [text('Privacy')],
+                ),
+              ]),
+              li([
+                a(
+                  href: '/security',
+                  attributes: {'title': 'Security philosophy and practices'},
+                  [text('Security')],
+                ),
+              ]),
+            ]),
+            div(classes: 'footer-technology', [
+              a(
+                classes: 'jaspr-badge-link',
+                href: 'https://jaspr.site',
+                target: Target.blank,
+                attributes: {
+                  'rel': 'noopener',
+                  'title':
+                      'This site is built with the '
+                      'Jaspr web framework for Dart.',
+                },
+                [
+                  span([const JasprBadge.light()]),
+                  span([const JasprBadge.lightTwoTone()]),
+                ],
+              ),
+            ]),
+          ]),
+        ]),
+      ],
+    );
+  }
+}
diff --git a/site/lib/src/components/layout/header.dart b/site/lib/src/components/layout/header.dart
new file mode 100644
index 00000000000..14a0d962f6e
--- /dev/null
+++ b/site/lib/src/components/layout/header.dart
@@ -0,0 +1,92 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+
+import '../common/button.dart';
+import '../common/material_icon.dart';
+import 'menu_toggle.dart';
+import 'site_switcher.dart';
+import 'theme_switcher.dart';
+
+/// The site-wide top navigation bar.
+class DashHeader extends StatelessComponent {
+  const DashHeader({super.key});
+
+  @override
+  Component build(BuildContext context) =>
+      header(id: 'site-header', classes: 'always-dark-mode', [
+        nav(classes: 'navbar', [
+          a(
+            id: 'site-primary-logo',
+            classes: 'site-wordmark',
+            href: '/',
+            attributes: {
+              'aria-label': 'Go to the Flutter docs homepage.',
+              'title': 'Go to the Flutter docs homepage.',
+            },
+            [
+              img(
+                src: '/assets/images/branding/flutter/logo/default.svg',
+                alt: 'Flutter logo',
+                attributes: {'width': '28'},
+              ),
+              span(
+                classes: 'name',
+                attributes: {'translate': 'no'},
+                [text('Flutter')],
+              ),
+              span(
+                classes: 'subtype',
+                [text('Docs')],
+              ),
+            ],
+          ),
+
+          div(
+            classes: 'navbar-contents',
+            [
+              form(
+                action: '/search/',
+                id: 'header-search',
+                [
+                  input(
+                    classes: 'search-field',
+                    type: InputType.search,
+                    name: 'q',
+                    id: 'q',
+                    attributes: {
+                      'autocomplete': 'off',
+                      'placeholder': 'Search',
+                      'aria-label': 'Search',
+                    },
+                  ),
+                ],
+              ),
+              a(
+                id: 'fallback-search-button',
+                classes: 'icon-button',
+                href: '/search',
+                attributes: {
+                  'aria-label': 'Navigate to the docs.flutter.dev search page.',
+                  'title': 'Navigate to the docs.flutter.dev search page.',
+                },
+                const [
+                  MaterialIcon('search'),
+                ],
+              ),
+              const ThemeSwitcher(),
+              const SiteSwitcher(),
+              const Button(
+                id: 'call-to-action',
+                style: ButtonStyle.filled,
+                content: 'Get started',
+                href: '/get-started/quick',
+              ),
+              const MenuToggle(),
+            ],
+          ),
+        ]),
+      ]);
+}
diff --git a/site/lib/src/components/layout/menu_toggle.dart b/site/lib/src/components/layout/menu_toggle.dart
new file mode 100644
index 00000000000..c2ee0f5b4ae
--- /dev/null
+++ b/site/lib/src/components/layout/menu_toggle.dart
@@ -0,0 +1,74 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:universal_web/js_interop.dart';
+import 'package:universal_web/web.dart' as web;
+
+import '../common/material_icon.dart';
+
+@client
+final class MenuToggle extends StatefulComponent {
+  const MenuToggle();
+
+  @override
+  State createState() => _MenuToggleState();
+}
+
+final class _MenuToggleState extends State {
+  @override
+  void initState() {
+    if (kIsWeb) {
+      // Set up an event listener to close the wide sidenav if
+      // switching to a wider site layout.
+      web.window.addEventListener('resize', _handleResize.toJS);
+
+      // Set up an event listener to close the sidenav
+      // if it is open and somewhere else is clicked on.
+      web.window.addEventListener('click', _handleClickOutsideSidenav.toJS);
+    }
+
+    super.initState();
+  }
+
+  @override
+  Component build(BuildContext context) => button(
+    id: 'menu-toggle',
+    classes: 'icon-button',
+    type: ButtonType.button,
+    attributes: {
+      'aria-controls': 'sidenav',
+      'aria-label': 'Toggle navigation menu.',
+      'title': 'Toggle navigation menu.',
+    },
+    events: {
+      'click': (_) {
+        web.document.body?.classList.toggle('open_menu');
+      },
+    },
+    const [
+      MaterialIcon('menu'),
+      MaterialIcon('close'),
+    ],
+  );
+}
+
+void _handleResize(web.Event _) {
+  if (web.window.innerWidth > 1025) {
+    web.document.body?.classList.remove('open_menu');
+  }
+}
+
+void _handleClickOutsideSidenav(web.MouseEvent clickEvent) {
+  if (clickEvent.target case final web.HTMLElement clickedElement) {
+    if (clickedElement.closest('#sidenav') == null &&
+        clickedElement.closest('#menu-toggle') == null) {
+      final bodyClasses = web.document.body!.classList;
+      if (bodyClasses.contains('open_menu')) {
+        clickEvent.preventDefault();
+        bodyClasses.remove('open_menu');
+      }
+    }
+  }
+}
diff --git a/site/lib/src/components/layout/sidenav.dart b/site/lib/src/components/layout/sidenav.dart
new file mode 100644
index 00000000000..ddd0f7909a4
--- /dev/null
+++ b/site/lib/src/components/layout/sidenav.dart
@@ -0,0 +1,338 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+
+import '../../models/sidenav_model.dart';
+import '../../util.dart';
+import '../common/material_icon.dart';
+
+/// The site-wide side navigation menu,
+/// with entries loaded from the `src/data/sidenav.yml` file.
+final class DashSideNav extends StatelessComponent {
+  const DashSideNav({
+    super.key,
+    required this.navEntries,
+    required this.currentPageUrl,
+  });
+
+  final List navEntries;
+
+  /// The URL of the current page to mark as active, alongside its ancestors.
+  final String currentPageUrl;
+
+  @override
+  Component build(BuildContext _) => div(id: 'sidenav', [
+    nav([
+      _SideNavLevel(
+        entries: navEntries,
+        parentId: 'sidenav',
+        currentLevel: 0,
+        possiblyActive: true,
+        currentPageUrl: currentPageUrl,
+        activePath: _ActiveNavigationPath.findActive(
+          entries: navEntries,
+          currentPageUrl: currentPageUrl,
+        ),
+      ),
+    ]),
+  ]);
+}
+
+class _SideNavLevel extends StatelessComponent {
+  const _SideNavLevel({
+    required this.entries,
+    required this.parentId,
+    required this.currentLevel,
+    required this.possiblyActive,
+    required this.currentPageUrl,
+    required this.activePath,
+    this.classes,
+    this.id,
+  });
+
+  final List entries;
+  final String parentId;
+  final int currentLevel;
+  final bool possiblyActive;
+  final String currentPageUrl;
+  final _ActiveNavigationPath activePath;
+  final String? classes;
+  final String? id;
+
+  @override
+  Component build(BuildContext _) => ul(
+    classes: classes,
+    id: id,
+    [
+      for (var entryIndex = 0; entryIndex < entries.length; entryIndex++)
+        _componentFromEntry(entryIndex),
+    ],
+  );
+
+  /// Builds the component that corresponds to the entry at
+  /// the specified [entryIndex] in [entries].
+  Component _componentFromEntry(int entryIndex) {
+    final entry = entries[entryIndex];
+
+    late final isInActivePath =
+        possiblyActive &&
+        activePath.isIndexActiveAtLevel(entryIndex, currentLevel);
+
+    return switch (entry) {
+      NavDivider() => const _SideNavDivider(),
+      NavHeader(:final title) => _SideNavHeader(title: title),
+      NavSection() => _SideNavCollapsibleSection(
+        section: entry,
+        id: _generateChildId(entryIndex),
+        isInActivePath: isInActivePath,
+        currentLevel: currentLevel,
+        currentPageUrl: currentPageUrl,
+        activePath: activePath,
+      ),
+      NavLink() => _SideNavLink(
+        entry,
+        isActive: isInActivePath && activePath.isLeafAt(currentLevel),
+      ),
+    };
+  }
+
+  String _generateChildId(int entryIndex) => '$parentId-${entryIndex + 1}';
+}
+
+class _SideNavDivider extends StatelessComponent {
+  const _SideNavDivider();
+
+  @override
+  Component build(BuildContext _) => li(
+    attributes: {'aria-hidden': 'true'},
+    [div(classes: 'sidenav-divider', [])],
+  );
+}
+
+class _SideNavHeader extends StatelessComponent {
+  const _SideNavHeader({required this.title});
+
+  final String title;
+
+  @override
+  Component build(BuildContext _) => li(classes: 'nav-header', [text(title)]);
+}
+
+class _SideNavCollapsibleSection extends StatelessComponent {
+  const _SideNavCollapsibleSection({
+    required this.section,
+    required this.id,
+    required this.isInActivePath,
+    required this.currentLevel,
+    required this.currentPageUrl,
+    required this.activePath,
+  });
+
+  final NavSection section;
+  final String id;
+  final bool isInActivePath;
+  final int currentLevel;
+  final String currentPageUrl;
+  final _ActiveNavigationPath activePath;
+
+  @override
+  Component build(BuildContext _) {
+    // Determine if children should be shown based on hiddenChildren setting.
+    final shouldShowChildren = _shouldShowChildren();
+
+    if (!shouldShowChildren) {
+      // When hiddenChildren is true and path doesn't match,
+      // render as a sidenav link if a permalink exists, otherwise as text.
+      return section.permalink != null
+          ? _SideNavLink(
+              NavLink(section.title, section.permalink!),
+              isActive: isInActivePath,
+            )
+          : li(classes: 'nav-item', [
+              span(classes: 'nav-link', [text(section.title)]),
+            ]);
+    }
+
+    final expanded = isInActivePath || section.expanded;
+    return li(classes: 'nav-item', [
+      button(
+        classes: [
+          'nav-link',
+          if (isInActivePath) 'active',
+          'collapsible',
+          if (!expanded) 'collapsed',
+        ].toClasses,
+        attributes: {
+          'data-toggle': 'collapse',
+          'data-target': '#$id',
+          'role': 'button',
+          'aria-expanded': expanded.toString(),
+          'aria-controls': id,
+        },
+        [
+          span([text(section.title)]),
+          const MaterialIcon('expand_more', classes: ['expander']),
+        ],
+      ),
+      _SideNavLevel(
+        entries: section.children,
+        parentId: id,
+        currentLevel: currentLevel + 1,
+        possiblyActive: isInActivePath,
+        currentPageUrl: currentPageUrl,
+        activePath: activePath,
+        classes: [
+          'nav',
+          'collapse',
+          if (expanded) 'show',
+        ].toClasses,
+        id: id,
+      ),
+    ]);
+  }
+
+  /// Determines whether children should be shown for this section.
+  ///
+  /// If [NavSection.hiddenChildren] is true, children are only shown
+  /// when the current page URL matches or is under the section's permalink.
+  bool _shouldShowChildren() {
+    if (!section.hiddenChildren) {
+      return true;
+    }
+
+    final permalink = section.permalink;
+    if (permalink == null) {
+      // No permalink to match against, show children.
+      return true;
+    }
+
+    // Normalize the permalink to ensure it starts with '/'.
+    final normalizedPermalink = _normalizePermalink(permalink);
+
+    // Show children if the current URL matches or is under this section.
+    return currentPageUrl == normalizedPermalink ||
+        currentPageUrl.startsWith('$normalizedPermalink/');
+  }
+}
+
+class _SideNavLink extends StatelessComponent {
+  const _SideNavLink(this.link, {this.isActive = false});
+
+  final NavLink link;
+  final bool isActive;
+
+  @override
+  Component build(BuildContext _) {
+    final isExternal = link.permalink.contains('://');
+    return li(classes: 'nav-item', [
+      a(
+        classes: ['nav-link', if (isActive) 'active'].toClasses,
+        href: link.permalink,
+        target: isExternal ? Target.blank : null,
+        attributes: isExternal ? {'rel': 'noopener'} : null,
+        [
+          div([
+            span([text(link.title)]),
+            if (isExternal) const MaterialIcon('open_in_new'),
+          ]),
+        ],
+      ),
+    ]);
+  }
+}
+
+/// Represents the active navigation path in the sidenav.
+///
+/// Encapsulates the logic for determining and checking
+/// the active navigation path based on the current page URL.
+final class _ActiveNavigationPath {
+  /// The indices representing the path to the active navigation entry.
+  final List _indices;
+
+  const _ActiveNavigationPath(this._indices);
+
+  /// An empty navigation path (no active item).
+  static const empty = _ActiveNavigationPath([]);
+
+  /// Finds the active navigation path for the specified [currentPageUrl].
+  factory _ActiveNavigationPath.findActive({
+    required List entries,
+    required String currentPageUrl,
+  }) {
+    final permalinkPaths = _collectPermalinkPaths(entries);
+    final bestMatch = _findBestMatchingPath(permalinkPaths, currentPageUrl);
+    return bestMatch != null ? _ActiveNavigationPath(bestMatch) : empty;
+  }
+
+  /// Returns whether the given [index] is active at the specified [level].
+  bool isIndexActiveAtLevel(int index, int level) {
+    assert(level >= 0);
+    return level < _indices.length && _indices[level] == index;
+  }
+
+  /// Returns whether the specified [level] represents the
+  /// leaf element in the active path.
+  bool isLeafAt(int level) =>
+      _indices.isNotEmpty && level == _indices.length - 1;
+
+  /// Collects all internal link permalinks and their navigation paths.
+  static Map> _collectPermalinkPaths(
+    List entries, [
+    List currentPath = const [],
+  ]) {
+    final results = >{};
+
+    for (var entryIndex = 0; entryIndex < entries.length; entryIndex++) {
+      final entry = entries[entryIndex];
+      final newPath = [...currentPath, entryIndex];
+
+      if (entry case NavLink(
+        :final permalink,
+      ) when !_isExternalLink(permalink)) {
+        final normalizedPermalink = _normalizePermalink(permalink);
+        results[normalizedPermalink] = newPath;
+      } else if (entry case NavSection(:final children)) {
+        results.addAll(_collectPermalinkPaths(children, newPath));
+      }
+    }
+
+    return results;
+  }
+
+  /// Finds the best matching navigation path for the given URL.
+  static List? _findBestMatchingPath(
+    Map> permalinkPaths,
+    String targetUrl,
+  ) {
+    String? bestMatchingPermalink;
+    List? bestMatchingPath;
+
+    for (final MapEntry(key: permalink, value: path)
+        in permalinkPaths.entries) {
+      if (_urlMatchesPermalink(targetUrl, permalink)) {
+        // Keep the longest (most specific) matching permalink.
+        if (bestMatchingPermalink == null ||
+            permalink.length > bestMatchingPermalink.length) {
+          bestMatchingPermalink = permalink;
+          bestMatchingPath = path;
+        }
+      }
+    }
+
+    return bestMatchingPath;
+  }
+
+  /// Returns whether the specified [url] matches the specified [permalink],
+  /// either exactly or as a parent path.
+  static bool _urlMatchesPermalink(String url, String permalink) =>
+      url == permalink || url.startsWith('$permalink/');
+
+  /// Returns whether the specified [permalink] is an external link.
+  static bool _isExternalLink(String permalink) => permalink.contains('://');
+}
+
+/// Normalizes a permalink to ensure it starts with '/'.
+String _normalizePermalink(String permalink) =>
+    permalink.startsWith('/') ? permalink : '/$permalink';
diff --git a/site/lib/src/components/layout/site_switcher.dart b/site/lib/src/components/layout/site_switcher.dart
new file mode 100644
index 00000000000..311b35f2bbc
--- /dev/null
+++ b/site/lib/src/components/layout/site_switcher.dart
@@ -0,0 +1,139 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+
+import '../../util.dart';
+import '../common/button.dart';
+import '../common/dropdown.dart';
+
+@client
+final class SiteSwitcher extends StatelessComponent {
+  const SiteSwitcher();
+
+  @override
+  Component build(BuildContext _) => Dropdown(
+    id: 'site-switcher',
+    children: [
+      const DropdownToggle(Button(icon: 'apps', title: 'Visit related sites.')),
+      DropdownContent(
+        nav(
+          classes: 'dropdown-menu',
+          attributes: {
+            'role': 'menu',
+          },
+          [
+            ul(
+              const [
+                _SiteWordMarkListEntry(
+                  name: 'Flutter',
+                  href: 'https://flutter.dev',
+                ),
+                _SiteWordMarkListEntry(
+                  name: 'Flutter',
+                  subtype: 'Docs',
+                  href: '/',
+                  current: true,
+                ),
+                _SiteWordMarkListEntry(
+                  name: 'Flutter',
+                  subtype: 'API',
+                  href: 'https://api.flutter.dev',
+                ),
+                _SiteWordMarkListEntry(
+                  name: 'Flutter',
+                  subtype: 'Blog',
+                  href: 'https://blog.flutter.dev',
+                ),
+                Component.element(
+                  tag: 'li',
+                  classes: 'dropdown-divider',
+                  attributes: {'aria-hidden': 'true', 'role': 'separator'},
+                ),
+                _SiteWordMarkListEntry(
+                  name: 'Dart',
+                  href: 'https://dart.dev',
+                  dart: true,
+                ),
+                _SiteWordMarkListEntry(
+                  name: 'DartPad',
+                  href: 'https://dartpad.dev',
+                  dart: true,
+                ),
+                _SiteWordMarkListEntry(
+                  name: 'pub.dev',
+                  href: 'https://pub.dev',
+                  dart: true,
+                ),
+              ],
+            ),
+          ],
+        ),
+      ),
+    ],
+  );
+}
+
+class _SiteWordMarkListEntry extends StatelessComponent {
+  const _SiteWordMarkListEntry({
+    required this.href,
+    required this.name,
+    this.subtype,
+    this.current = false,
+    this.dart = false,
+  });
+
+  final bool dart;
+  final String href;
+  final String name;
+  final String? subtype;
+  final bool current;
+
+  String get _combinedName => '$name${subtype != null ? ' $subtype' : ''}';
+
+  @override
+  Component build(BuildContext _) {
+    return li(
+      attributes: {'role': 'presentation'},
+      [
+        a(
+          href: href,
+          classes: ['site-wordmark', if (current) 'current-site'].toClasses,
+          attributes: {
+            'role': 'menuitem',
+            'title': 'Navigate to the $_combinedName website.',
+            'aria-label': 'Navigate to the $_combinedName website.',
+          },
+          [
+            if (dart)
+              img(
+                src: '/assets/images/branding/dart/logo.svg',
+                alt: 'Dart logo',
+                width: 28,
+                height: 28,
+              )
+            else
+              img(
+                src: '/assets/images/branding/flutter/logo/default.svg',
+                alt: 'Flutter logo',
+                width: 28,
+              ),
+            span(
+              classes: 'name',
+              attributes: {
+                'translate': 'no',
+              },
+              [text(name)],
+            ),
+            if (subtype case final subtype?)
+              span(
+                classes: 'subtype',
+                [text(subtype)],
+              ),
+          ],
+        ),
+      ],
+    );
+  }
+}
diff --git a/site/lib/src/components/layout/theme_switcher.dart b/site/lib/src/components/layout/theme_switcher.dart
new file mode 100644
index 00000000000..9227d6d7631
--- /dev/null
+++ b/site/lib/src/components/layout/theme_switcher.dart
@@ -0,0 +1,139 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:universal_web/web.dart' as web;
+
+import '../common/button.dart';
+import '../common/dropdown.dart';
+import '../common/material_icon.dart';
+
+@client
+final class ThemeSwitcher extends StatefulComponent {
+  const ThemeSwitcher();
+
+  @override
+  State createState() => _ThemeSwitcherState();
+}
+
+enum _Theme {
+  light('Light', 'Switch to the light theme.', 'light_mode'),
+  dark('Dark', 'Switch to the dark theme.', 'dark_mode'),
+  auto('Automatic', 'Match theme to device theme.', 'night_sight_auto');
+
+  final String label;
+  final String description;
+  final String iconId;
+
+  const _Theme(this.label, this.description, this.iconId);
+
+  String get id => '$name-mode';
+}
+
+final class _ThemeSwitcherState extends State {
+  _Theme _currentTheme = _Theme.light;
+
+  @override
+  void initState() {
+    if (kIsWeb) {
+      final classList = web.document.body!.classList;
+      // If them theme is auto, it and the result will be added as classes.
+      // So it should be checked for first.
+      if (classList.contains(_Theme.auto.id)) {
+        _currentTheme = _Theme.auto;
+      } else if (classList.contains(_Theme.dark.id)) {
+        _currentTheme = _Theme.dark;
+      } else if (classList.contains(_Theme.light.id)) {
+        _currentTheme = _Theme.light;
+      } else {
+        // Default to light mode if no theme is set yet.
+        _currentTheme = _Theme.light;
+        classList.add(_Theme.light.id);
+      }
+    }
+
+    super.initState();
+  }
+
+  void _setTheme(_Theme newTheme) {
+    if (newTheme == _currentTheme) return;
+
+    final classList = web.document.body!.classList;
+    for (final mode in _Theme.values) {
+      classList.remove(mode.id);
+    }
+    classList.add(newTheme.id);
+    if (newTheme == _Theme.auto) {
+      classList.add(
+        web.window.matchMedia('(prefers-color-scheme: dark)').matches
+            ? _Theme.dark.id
+            : _Theme.light.id,
+      );
+    }
+
+    web.window.localStorage.setItem('theme', newTheme.id);
+
+    setState(() {
+      _currentTheme = newTheme;
+    });
+  }
+
+  @override
+  Component build(BuildContext _) => Dropdown(
+    id: 'theme-switcher',
+    children: [
+      const DropdownToggle(Button(icon: 'routine', title: 'Select a theme.')),
+      DropdownContent(
+        div(
+          classes: 'dropdown-menu',
+          [
+            ul(
+              attributes: {'role': 'listbox'},
+              [
+                for (final mode in _Theme.values)
+                  _ThemeButtonEntry(
+                    mode: mode,
+                    selected: _currentTheme == mode,
+                    setMode: _setTheme,
+                  ),
+              ],
+            ),
+          ],
+        ),
+      ),
+    ],
+  );
+}
+
+final class _ThemeButtonEntry extends StatelessComponent {
+  const _ThemeButtonEntry({
+    required this.mode,
+    required this.selected,
+    required this.setMode,
+  });
+
+  final _Theme mode;
+  final bool selected;
+  final void Function(_Theme) setMode;
+
+  @override
+  Component build(BuildContext _) => li([
+    button(
+      events: {
+        'click': (_) {
+          setMode(mode);
+        },
+      },
+      attributes: {
+        'title': mode.description,
+        'aria-label': mode.description,
+        'aria-selected': selected.toString(),
+      },
+      [
+        MaterialIcon(mode.iconId),
+        span([text(mode.label)]),
+      ],
+    ),
+  ]);
+}
diff --git a/site/lib/src/components/layout/toc.dart b/site/lib/src/components/layout/toc.dart
new file mode 100644
index 00000000000..3721ff1d66c
--- /dev/null
+++ b/site/lib/src/components/layout/toc.dart
@@ -0,0 +1,112 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+
+import '../../models/on_this_page_model.dart';
+import '../common/client/on_this_page_button.dart';
+import '../common/material_icon.dart';
+
+final class WideTableOfContents extends StatelessComponent {
+  const WideTableOfContents(this.data);
+
+  final OnThisPageData data;
+
+  @override
+  Component build(BuildContext _) {
+    return nav(id: 'toc-side', classes: 'site-toc', [
+      const OnThisPageButton(),
+      _TocContents(data),
+    ]);
+  }
+}
+
+final class NarrowTableOfContents extends StatelessComponent {
+  const NarrowTableOfContents(
+    this.data, {
+    required this.currentTitle,
+  });
+
+  final OnThisPageData data;
+  final String currentTitle;
+
+  @override
+  Component build(BuildContext _) {
+    return div(id: 'toc-top', classes: 'site-toc dropdown', [
+      button(
+        classes: 'dropdown-button',
+        attributes: {
+          'title': 'Toggle the table of contents dropdown',
+          'aria-expanded': 'false',
+          'aria-controls': 'toc-dropdown',
+          'aria-label': 'Toggle the table of contents dropdown',
+        },
+        [
+          span(classes: 'toc-intro', [
+            const MaterialIcon('list'),
+            span(
+              attributes: {'aria-label': 'On this page'},
+              [
+                text('On this page'),
+              ],
+            ),
+          ]),
+          span(classes: 'toc-current', [
+            const MaterialIcon('chevron_right'),
+            span(id: 'current-header', [text(currentTitle)]),
+          ]),
+        ],
+      ),
+      div(id: 'toc-dropdown', classes: 'dropdown-content', [
+        a(
+          href: '#site-content-title',
+          id: 'return-to-top',
+          [
+            const MaterialIcon('vertical_align_top'),
+            span([text(currentTitle)]),
+          ],
+        ),
+        div(
+          classes: 'dropdown-divider',
+          attributes: {'aria-hidden': 'true', 'role': 'separator'},
+          [],
+        ),
+        nav(
+          attributes: {'role': 'menu'},
+          [_TocContents(data)],
+        ),
+      ]),
+    ]);
+  }
+}
+
+final class _TocContents extends StatelessComponent {
+  const _TocContents(this.data);
+
+  final OnThisPageData data;
+
+  @override
+  Component build(BuildContext _) => ul(
+    classes: 'styled-toc-list',
+    _buildEntries(data.topLevelEntries, 0),
+  );
+
+  List _buildEntries(List entries, int depth) {
+    final nextDepth = depth + 1;
+
+    return [
+      for (final entry in entries)
+        li([
+          span(classes: 'sidenav-item', [
+            a(
+              href: '#${entry.id}',
+              [text(entry.text)],
+            ),
+          ]),
+          if (entry.children.isNotEmpty)
+            ul(_buildEntries(entry.children, nextDepth)),
+        ]),
+    ];
+  }
+}
diff --git a/site/lib/src/components/layout/trailing_content.dart b/site/lib/src/components/layout/trailing_content.dart
new file mode 100644
index 00000000000..4051200526c
--- /dev/null
+++ b/site/lib/src/components/layout/trailing_content.dart
@@ -0,0 +1,89 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../common/client/feedback.dart';
+
+/// The trailing content of a content documentation page, such as
+/// its last updated information, report an issue links, and similar.
+class TrailingContent extends StatelessComponent {
+  const TrailingContent({super.key, this.repo});
+
+  final String? repo;
+
+  @override
+  Component build(BuildContext context) {
+    final page = context.page;
+    final pageUrl = page.url;
+    final pageData = page.data.page;
+    final siteData = page.data.site;
+    final branch = siteData['branch'] as String? ?? 'main';
+    final repoLinks = siteData['repo'] as Map? ?? {};
+    final repoUrl =
+        repo ??
+        repoLinks['this'] as String? ??
+        'https://github.com/dart-lang/site-www';
+    final inputPath = pageData['inputPath'] as String?;
+    final pageDate = pageData['date'] as String?;
+
+    final currentFlutterVersion =
+        siteData['currentFlutterVersion'] as String? ?? '';
+    final siteUrl = siteData['url'] as String? ?? 'https://docs.flutter.dev';
+
+    final fullPageUrl = '$siteUrl$pageUrl';
+    final String issueUrl;
+    final String? pageSource;
+
+    if (inputPath != null) {
+      pageSource = '$repoUrl/blob/$branch/${inputPath.replaceAll('./', '')}';
+      issueUrl =
+          '$repoUrl/issues/new?template=1_page_issue.yml&page-url=$fullPageUrl&page-source=$pageSource';
+    } else {
+      pageSource = null;
+      issueUrl =
+          '$repoUrl/issues/new?template=1_page_issue.yml&page-url=$fullPageUrl';
+    }
+
+    return div(
+      id: 'trailing-content',
+      attributes: {'data-nosnippet': 'true'},
+      [
+        FeedbackComponent(issueUrl: issueUrl),
+
+        p(id: 'page-github-links', [
+          span([
+            text(
+              'Unless stated otherwise, the documentation on '
+              'this site reflects Flutter $currentFlutterVersion. ',
+            ),
+            if (pageDate != null)
+              text(
+                'Page last updated on $pageDate. ',
+              ),
+          ]),
+          if (pageSource != null) ...[
+            a(
+              href: pageSource,
+              attributes: {'target': '_blank', 'rel': 'noopener'},
+              [text('View source')],
+            ),
+            span([text(' or ')]),
+          ],
+          a(
+            href: issueUrl,
+            attributes: {
+              'title': 'Report an issue with this page',
+              'target': '_blank',
+              'rel': 'noopener',
+            },
+            [text(pageSource == null ? 'Report an issue' : 'report an issue')],
+          ),
+          text('.'),
+        ]),
+      ],
+    );
+  }
+}
diff --git a/site/lib/src/components/pages/archive_table.dart b/site/lib/src/components/pages/archive_table.dart
new file mode 100644
index 00000000000..58d81276c10
--- /dev/null
+++ b/site/lib/src/components/pages/archive_table.dart
@@ -0,0 +1,167 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:meta/meta.dart';
+
+import '../../models/flutter_release_model.dart';
+
+@client
+class ArchiveTable extends StatefulComponent {
+  const ArchiveTable({required this.os, required this.channel, super.key});
+
+  /// Creates an [ArchiveTable] from a set of attributes parsed from markdown.
+  factory ArchiveTable.fromAttributes(Map attributes) {
+    final os =
+        attributes['os'] ??
+        (throw Exception('ArchiveTable component requires an "os" attribute.'));
+    final channel =
+        attributes['channel'] ??
+        (throw Exception(
+          'ArchiveTable component requires a "channel" attribute.',
+        ));
+    return ArchiveTable(os: os.toLowerCase(), channel: channel.toLowerCase());
+  }
+
+  final String os;
+  final String channel;
+
+  @override
+  State createState() => _ArchiveTableState();
+}
+
+class _ArchiveTableState extends State {
+  String get os => component.os;
+  String get channel => component.channel;
+
+  bool isLoading = true;
+  String? error;
+  List releases = [];
+
+  @override
+  void initState() {
+    super.initState();
+
+    if (kIsWeb) {
+      loadReleases();
+    }
+  }
+
+  @awaitNotRequired
+  Future loadReleases() async {
+    try {
+      final releasesData = await FlutterRelease.fetchFlutterReleases(
+        component.os,
+      );
+      final filteredReleases = releasesData
+          .where((release) => release.channel == channel)
+          .toList();
+
+      setState(() {
+        releases = filteredReleases;
+        isLoading = false;
+      });
+    } catch (e) {
+      setState(() {
+        error = e.toString();
+        isLoading = false;
+      });
+    }
+  }
+
+  @override
+  Component build(BuildContext context) {
+    return Component.fragment([
+      p([
+        text('Select from the following scrollable list:'),
+      ]),
+      div(classes: 'scrollable-table table-wrapper', [
+        table(
+          id: 'downloads-$os-$channel',
+          classes: 'table table-striped',
+          [
+            thead([
+              tr([
+                th([text('Flutter version')]),
+                th([text('Architecture')]),
+                th([text('Ref')]),
+                th(classes: 'date', [text('Release Date')]),
+                th([text('Dart version')]),
+                th([text('Provenance')]),
+              ]),
+            ]),
+            tbody([
+              if (isLoading)
+                tr(classes: 'loading', [
+                  td(attributes: {'colspan': '6'}, [text('Loading...')]),
+                ])
+              else if (error != null)
+                tr(classes: 'error', [
+                  td(
+                    attributes: {'colspan': '6'},
+                    [
+                      text(
+                        'Failed to load releases. Refresh page to try again.',
+                      ),
+                    ],
+                  ),
+                ])
+              else
+                for (final release in releases)
+                  tr([
+                    td([
+                      a(href: release.url, [
+                        text(release.version),
+                      ]),
+                    ]),
+                    td([
+                      span([text(release.architecture)]),
+                    ]),
+                    td([
+                      span(classes: 'git-hash', [text(release.hash)]),
+                    ]),
+                    td(classes: 'date', [
+                      text(
+                        release.releaseDate.toLocaleDateString(),
+                      ),
+                    ]),
+                    td([
+                      span([text(release.dartSdkVersion)]),
+                    ]),
+                    td([
+                      buildProvenanceLink(release),
+                    ]),
+                  ]),
+            ]),
+          ],
+        ),
+      ]),
+    ]);
+  }
+
+  static final windowsCutoff = Date.parse('4/3/2023');
+  static final otherOsCutoff = Date.parse('12/15/2022');
+
+  Component buildProvenanceLink(FlutterRelease release) {
+    final dateValue = release.releaseDate.valueOf();
+
+    if (os == 'windows' && dateValue < windowsCutoff) {
+      // Provenance not available before 4/3/2023 for Windows
+      return span([text('-')]);
+    } else if (dateValue < otherOsCutoff) {
+      // Provenance not available before 12/15/2022 for macOS and Linux
+      return span([text('-')]);
+    }
+
+    final archiveExtension = os == 'linux' ? 'tar.xz' : 'zip';
+    return a(
+      href:
+          '${FlutterRelease.baseReleasesUrl}$channel/$os/'
+          'flutter_${os}_${release.version}-$channel.'
+          '$archiveExtension.intoto.jsonl',
+      target: Target.blank,
+      [text('Attestation bundle')],
+    );
+  }
+}
diff --git a/site/lib/src/components/pages/devtools_release_notes_index.dart b/site/lib/src/components/pages/devtools_release_notes_index.dart
new file mode 100644
index 00000000000..37f1846158e
--- /dev/null
+++ b/site/lib/src/components/pages/devtools_release_notes_index.dart
@@ -0,0 +1,43 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:collection/collection.dart';
+import 'package:jaspr/jaspr.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+import 'package:pub_semver/pub_semver.dart';
+
+class DevToolsReleaseNotesIndex extends StatelessComponent {
+  const DevToolsReleaseNotesIndex({super.key});
+
+  static List<({Version version, Page page})> findDevToolsReleases(
+    BuildContext context,
+  ) {
+    const releaseNotesPrefix = 'tools/devtools/release-notes/release-notes-';
+    return context.pages
+        .where((p) => p.path.startsWith(releaseNotesPrefix))
+        .map(
+          (p) => (
+            version: Version.parse(p.data.page['breadcrumb'] as String),
+            page: p,
+          ),
+        )
+        .sortedBy((e) => e.version)
+        .reversed
+        .toList();
+  }
+
+  @override
+  Component build(BuildContext context) {
+    final releases = findDevToolsReleases(context);
+
+    return ul([
+      for (final release in releases)
+        li([
+          a(href: release.page.url, [
+            text(release.page.data.page['shortTitle'] as String),
+          ]),
+        ]),
+    ]);
+  }
+}
diff --git a/site/lib/src/components/pages/expansion_list.dart b/site/lib/src/components/pages/expansion_list.dart
new file mode 100644
index 00000000000..48511c3d166
--- /dev/null
+++ b/site/lib/src/components/pages/expansion_list.dart
@@ -0,0 +1,189 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:collection/collection.dart';
+import 'package:jaspr/jaspr.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+import 'package:path/path.dart' as path;
+
+import '../../markdown/markdown_parser.dart';
+import '../../util.dart';
+
+class ExpansionListItem {
+  ExpansionListItem({
+    required this.data,
+    required this.content,
+    required this.url,
+    this.expanded = false,
+    this.order = 0,
+  });
+
+  factory ExpansionListItem.fromPage(Page page) {
+    final data = page.data.page;
+    final content = truncateWordsMarkdown(page.content, 100);
+    try {
+      return ExpansionListItem(
+        data: ExpansionListItemData(
+          title: data['title'] as String,
+          description: data['description'] as String,
+          contentTags: (data['contentTags'] as List).cast(),
+          iconPath: data['iconPath'] as String?,
+        ),
+        content: content,
+        url: page.url,
+        expanded: data['expanded'] as bool? ?? false,
+        order: data['order'] as int? ?? 0,
+      );
+    } catch (e) {
+      throw Exception(
+        'Error parsing ExpansionListItem from page ${page.path}.\n'
+        'Ensure that all required frontmatter fields are present and '
+        'of the correct type.\nError details: $e',
+      );
+    }
+  }
+
+  final ExpansionListItemData data;
+  final String content;
+  final String url;
+  final bool expanded;
+  final int order;
+}
+
+class ExpansionListItemData {
+  ExpansionListItemData({
+    required this.title,
+    required this.description,
+    required this.contentTags,
+    required this.iconPath,
+  });
+
+  final String title;
+  final String description;
+  final List contentTags;
+  final String? iconPath;
+}
+
+class ExpansionList extends StatefulComponent {
+  const ExpansionList({required this.baseId, this.items = const [], super.key});
+
+  final String baseId;
+  final List items;
+
+  /// Creates an [ExpansionList] from a set of attributes parsed from markdown.
+  ///
+  /// The items are found by locating all pages under the path specified by the
+  /// 'list' attribute, which is relative to the current page's path.
+  ///
+  /// Pages are sorted by their `order` frontmatter value.
+  static Component fromAttributes(Map attributes) {
+    final listName =
+        attributes['list'] ??
+        (throw Exception(
+          'ExpansionList component requires a "list" attribute.',
+        ));
+    final baseId =
+        attributes['baseid'] ??
+        (throw Exception(
+          'ExpansionList component requires a "baseId" attribute.',
+        ));
+
+    return Builder(
+      builder: (context) {
+        final listPath = path.join(
+          path.dirname(context.page.path),
+          listName + path.separator,
+        );
+        final items = [
+          for (final page in context.pages)
+            if (page.path.startsWith(listPath) && page.path.endsWith('.md'))
+              ExpansionListItem.fromPage(page),
+        ].sorted((a, b) => a.order.compareTo(b.order));
+
+        return ExpansionList(
+          key: ValueKey(listName),
+          baseId: baseId,
+          items: items,
+        );
+      },
+    );
+  }
+
+  @override
+  State createState() => _ExpansionListState();
+}
+
+class _ExpansionListState extends State {
+  @override
+  Component build(BuildContext context) {
+    return div(classes: 'expansion-panel-list', [
+      for (final (index, item) in component.items.indexed)
+        div(classes: 'expansion-panel', [
+          a(
+            classes: ['collapsible', if (!item.expanded) 'collapsed'].toClasses,
+            href: '#${component.baseId}-expansion-$index',
+            attributes: {
+              'data-toggle': 'collapse',
+              'data-target': '#${component.baseId}-expansion-$index',
+              'role': 'button',
+              'aria-expanded': item.expanded ? 'true' : 'false',
+              'aria-controls': '#${component.baseId}-expansion-$index',
+            },
+            [
+              div(classes: 'expansion-panel-title', [
+                div(classes: 'expansion-panel-title-leading', [
+                  if (item.data.iconPath case final iconPath?)
+                    img(
+                      src: iconPath,
+                      alt: 'An icon showing a generic application.',
+                    )
+                  else
+                    img(
+                      src:
+                          '/assets/images/docs/app-architecture/design-patterns/kv-store-icon.svg',
+                      alt: 'An icon showing a generic application.',
+                    ),
+                ]),
+                div(classes: 'expansion-panel-title-content', [
+                  p(classes: 'content-title', [
+                    text(item.data.title),
+                  ]),
+                  ul(classes: 'content-tags', [
+                    for (final contentTag in item.data.contentTags)
+                      li(classes: 'tag', [
+                        text(contentTag),
+                      ]),
+                  ]),
+                  p(classes: 'content-description', [
+                    text(item.data.description),
+                  ]),
+                ]),
+              ]),
+            ],
+          ),
+          div(
+            id: '${component.baseId}-expansion-$index',
+            classes: [
+              'expansion-panel-body collapse',
+              if (item.expanded) 'show',
+            ].toClasses,
+            [
+              DashMarkdown(content: item.content),
+              p([
+                a(href: item.url, [
+                  text('Read full article'),
+                ]),
+              ]),
+              // Required to add "margin" that doesn't cause expansion jank.
+              div(
+                classes: 'separator',
+                attributes: {'aria-hidden': 'true'},
+                [],
+              ),
+            ],
+          ),
+        ]),
+    ]);
+  }
+}
diff --git a/site/lib/src/components/pages/learning_resource_filters.dart b/site/lib/src/components/pages/learning_resource_filters.dart
new file mode 100644
index 00000000000..37abf025721
--- /dev/null
+++ b/site/lib/src/components/pages/learning_resource_filters.dart
@@ -0,0 +1,196 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:math';
+
+import 'package:jaspr/jaspr.dart';
+import 'package:universal_web/js_interop.dart';
+import 'package:universal_web/web.dart' as web;
+
+import '../../analytics/analytics.dart';
+import '../../models/learning_resource_model.dart';
+import '../common/material_icon.dart';
+import '../util/global_event_listener.dart';
+import 'learning_resource_filters_sidebar.dart';
+
+@client
+class LearningResourceFilters extends StatefulComponent {
+  const LearningResourceFilters({super.key});
+
+  @override
+  State createState() =>
+      _LearningResourceFiltersState();
+}
+
+class _LearningResourceFiltersState extends State {
+  String searchQuery = '';
+
+  FiltersNotifier get filters => LearningResourceFiltersSidebar.filters;
+
+  final List resources = [];
+  int filteredResourcesCount = 0;
+
+  @override
+  void initState() {
+    super.initState();
+
+    if (kIsWeb) {
+      filters.addListener(setFilters);
+
+      final resourceGrid = web.document.getElementById('all-resources-grid');
+      if (resourceGrid == null) {
+        return;
+      }
+
+      final resourceCards = resourceGrid.querySelectorAll('.card');
+      recreateResources(resourceCards);
+      shuffleCards(resourceGrid);
+    }
+  }
+
+  void recreateResources(web.NodeList resourceCards) {
+    for (var i = 0; i < resourceCards.length; i++) {
+      final element = resourceCards.item(i) as web.Element;
+      final info = LearningResource.fromElement(element);
+      resources.add(info);
+
+      element.addEventListener(
+        'click',
+        ((web.Event event) {
+          analytics.sendEvent('learning_resource_index_click', {
+            'learning_resource_type': info.type,
+            'learning_resource_title': info.name,
+          });
+        }).toJS,
+      );
+    }
+    filteredResourcesCount = resources.length;
+  }
+
+  void shuffleCards(web.Element container) {
+    final r = Random();
+    final elements = container.childNodes;
+    for (var i = elements.length; i > 0; i--) {
+      final card = elements.item(r.nextInt(i));
+      container.appendChild(card!);
+    }
+  }
+
+  /// Update the filter state and re-evaluate which resources to show.
+  ///
+  /// Use like the `setState` method by passing a callback that updates
+  /// the relevant state variables.
+  ///
+  /// Example:
+  ///
+  /// ```dart
+  /// setFilters(() {
+  ///   searchQuery = '...';
+  /// });
+  /// ```
+  void setFilters([void Function()? callback]) {
+    setState(callback ?? () {});
+
+    final resourcesToShow = filters.filterResources(resources, searchQuery);
+    filteredResourcesCount = resourcesToShow.length;
+    for (final info in resources) {
+      final element =
+          web.document.getElementById(info.name) as web.HTMLElement?;
+      if (element == null) {
+        continue;
+      }
+
+      if (resourcesToShow.contains(info)) {
+        element.classList.remove('hidden');
+      } else {
+        element.classList.add('hidden');
+      }
+    }
+  }
+
+  @override
+  void dispose() {
+    if (kIsWeb) {
+      filters.removeListener(setFilters);
+    }
+    super.dispose();
+  }
+
+  @override
+  Component build(BuildContext context) {
+    return div(id: 'resource-search-group', classes: 'chip-filters-group', [
+      div(classes: 'top-row', [
+        div(classes: 'search-wrapper', id: 'resource-search', [
+          const MaterialIcon('search', classes: ['leading-icon']),
+          input(
+            type: InputType.search,
+            attributes: {
+              'placeholder': 'Try "button" or "networking"...',
+              'aria-label': 'Search learning resources by name and category',
+            },
+            value: searchQuery,
+            onInput: (value) {
+              setFilters(() {
+                searchQuery = value as String;
+              });
+            },
+          ),
+        ]),
+        GlobalEventListener(
+          onClick: (event) {
+            final target = event.target as web.Element?;
+            // If clicking outside the filters or toggle, close the filters.
+            if (target?.closest('#resource-filter-group-wrapper') == null &&
+                target?.closest('.show-filters-button') == null) {
+              final toggle =
+                  web.document.getElementById('open-filter-toggle')
+                      as web.HTMLInputElement?;
+              toggle?.checked = false;
+            }
+          },
+          button(
+            classes: 'icon-button show-filters-button',
+            onClick: () {
+              final toggle =
+                  web.document.getElementById('open-filter-toggle')
+                      as web.HTMLInputElement?;
+              toggle?.checked = !toggle.checked;
+            },
+            [
+              const MaterialIcon('filter_list'),
+            ],
+          ),
+        ),
+      ]),
+      div(classes: 'label-row', [
+        label(
+          attributes: {'for': 'resource-search'},
+          [
+            text('Showing '),
+            span([text('$filteredResourcesCount')]),
+            text(' / '),
+            span([text('${resources.length}')]),
+          ],
+        ),
+        button(
+          attributes: {
+            if (searchQuery.isEmpty &&
+                filters.selectedTags.isEmpty &&
+                filters.selectedTypes.isEmpty)
+              'disabled': 'true',
+          },
+          onClick: () {
+            // No setState needed, since resetting filters will trigger it.
+            searchQuery = '';
+            filters.reset();
+          },
+          [
+            const MaterialIcon('close_small'),
+            span([text('Clear filters')]),
+          ],
+        ),
+      ]),
+    ]);
+  }
+}
diff --git a/site/lib/src/components/pages/learning_resource_filters_sidebar.dart b/site/lib/src/components/pages/learning_resource_filters_sidebar.dart
new file mode 100644
index 00000000000..5a23001157e
--- /dev/null
+++ b/site/lib/src/components/pages/learning_resource_filters_sidebar.dart
@@ -0,0 +1,206 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+
+import '../../analytics/analytics.dart';
+import '../../models/learning_resource_model.dart';
+import '../../util.dart';
+import '../common/material_icon.dart';
+import 'learning_resource_filters.dart';
+
+@client
+class LearningResourceFiltersSidebar extends StatelessComponent {
+  const LearningResourceFiltersSidebar({super.key});
+
+  /// The filter state for the resources list.
+  ///
+  /// This is static so that [LearningResourceFilters] can access it,
+  /// since both client components don't share a common ancestor.
+  static FiltersNotifier filters = FiltersNotifier();
+
+  @override
+  Component build(BuildContext context) {
+    return div(classes: 'right-col', [
+      input(
+        type: InputType.checkbox,
+        id: 'open-filter-toggle',
+        attributes: {'hidden': 'true'},
+      ),
+      div(id: 'resource-filter-group-wrapper', [
+        div(id: 'resource-filter-group', [
+          div(classes: 'filter-header', [
+            label(
+              attributes: {'for': 'open-filter-toggle', 'aria-hidden': 'true'},
+              classes: 'close-icon',
+              [const MaterialIcon('close')],
+            ),
+          ]),
+          div(classes: 'table-title', [text('Filter by')]),
+          ListenableBuilder(
+            listenable: filters,
+            builder: (context) {
+              return div(classes: 'table-content', [
+                h4([text('Subject')]),
+                ul(classes: filters.tagsExpanded ? '' : 'collapsed', [
+                  for (final (index, tag) in LearningResourceTag.values.indexed)
+                    li(
+                      classes: [
+                        if (!filters.tagsExpanded && index > 3) 'hidden',
+                      ].toClasses,
+                      [
+                        input(
+                          type: InputType.checkbox,
+                          attributes: {
+                            'role': 'checkbox',
+                            'name': 'filter-${tag.name}',
+                          },
+                          id: 'filter-${tag.name}',
+                          checked: filters.selectedTags.contains(tag),
+                          onChange: (checked) {
+                            filters.setTag(tag, checked as bool);
+                          },
+                        ),
+                        label(
+                          attributes: {'for': 'filter-${tag.name}'},
+                          [text(tag.label)],
+                        ),
+                      ],
+                    ),
+                ]),
+                button(onClick: filters.toggleTagsExpanded, [
+                  span(classes: 'label', [
+                    text(filters.tagsExpanded ? 'Less' : 'More'),
+                  ]),
+                  MaterialIcon(
+                    filters.tagsExpanded ? 'expand_less' : 'expand_more',
+                  ),
+                ]),
+                h4([text('Type')]),
+                ul([
+                  for (final type in LearningResourceType.values)
+                    li([
+                      input(
+                        type: InputType.checkbox,
+                        attributes: {
+                          'role': 'checkbox',
+                          'name': 'filter-${type.name}',
+                        },
+                        id: 'filter-${type.name}',
+                        checked: filters.selectedTypes.contains(type),
+                        onChange: (checked) {
+                          filters.setType(type, checked as bool);
+                        },
+                      ),
+                      label(
+                        attributes: {'for': 'filter-${type.name}'},
+                        [text(type.label)],
+                      ),
+                    ]),
+                ]),
+              ]);
+            },
+          ),
+        ]),
+      ]),
+    ]);
+  }
+}
+
+/// Notifier to manage the state of the filters.
+class FiltersNotifier extends ChangeNotifier {
+  Set selectedTags = {};
+  Set selectedTypes = {};
+
+  bool tagsExpanded = false;
+
+  void setTag(LearningResourceTag tag, bool isSelected) {
+    if (isSelected) {
+      selectedTags.add(tag);
+
+      analytics.sendEvent(
+        'learning_resource_index_filter_selected',
+        {
+          'learning_resource_filter_name': tag.label.toLowerCase(),
+          'learning_resource_filter_type': 'tags',
+        },
+      );
+    } else {
+      selectedTags.remove(tag);
+    }
+    notifyListeners();
+  }
+
+  void setType(LearningResourceType type, bool isSelected) {
+    if (isSelected) {
+      selectedTypes.add(type);
+
+      analytics.sendEvent(
+        'learning_resource_index_filter_selected',
+        {
+          'learning_resource_filter_name': type.label.toLowerCase(),
+          'learning_resource_filter_type': 'type',
+        },
+      );
+    } else {
+      selectedTypes.remove(type);
+    }
+    notifyListeners();
+  }
+
+  void toggleTagsExpanded() {
+    tagsExpanded = !tagsExpanded;
+    notifyListeners();
+  }
+
+  void reset() {
+    selectedTags.clear();
+    selectedTypes.clear();
+    notifyListeners();
+  }
+
+  Set filterResources(
+    List resources,
+    String searchQuery,
+  ) {
+    if (searchQuery.isEmpty && selectedTags.isEmpty && selectedTypes.isEmpty) {
+      // No filters applied, return all resources.
+      return resources.toSet();
+    }
+
+    final resourcesToShow = {};
+    searchQuery = searchQuery.trim().toLowerCase();
+
+    final filterTags = selectedTags.expand((e) => e.tags).toSet();
+    final filterTypes = selectedTypes.expand((e) => e.tags).toSet();
+
+    for (final info in resources) {
+      final matchesTags =
+          selectedTags.isEmpty || info.tags.any(filterTags.contains);
+      if (!matchesTags) {
+        continue;
+      }
+
+      final matchesTypes =
+          selectedTypes.isEmpty || filterTypes.contains(info.type);
+      if (!matchesTypes) {
+        continue;
+      }
+
+      final matchesSearchQuery =
+          searchQuery.isEmpty ||
+          info.name.toLowerCase().contains(searchQuery) ||
+          info.tags.any((t) => t.contains(searchQuery)) ||
+          info.type.contains(searchQuery) ||
+          info.description.toLowerCase().contains(searchQuery);
+      if (!matchesSearchQuery) {
+        continue;
+      }
+
+      resourcesToShow.add(info);
+    }
+
+    return resourcesToShow;
+  }
+}
diff --git a/site/lib/src/components/pages/learning_resource_index.dart b/site/lib/src/components/pages/learning_resource_index.dart
new file mode 100644
index 00000000000..a55a9353cf6
--- /dev/null
+++ b/site/lib/src/components/pages/learning_resource_index.dart
@@ -0,0 +1,146 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../../models/learning_resource_model.dart';
+import '../../util.dart';
+import 'learning_resource_filters.dart';
+import 'learning_resource_filters_sidebar.dart';
+
+final class LearningResourceIndex extends StatelessComponent {
+  LearningResourceIndex({super.key});
+
+  @override
+  Component build(BuildContext context) {
+    final resourcesData =
+        context.page.data['learning-resources-index'] as Map?;
+
+    final learningResources = [];
+    if (resourcesData != null) {
+      for (final group in resourcesData.values) {
+        for (final resource in group as List) {
+          learningResources.add(
+            LearningResource.fromMap(resource as Map),
+          );
+        }
+      }
+    }
+
+    return div(id: 'resource-index-content', [
+      div(classes: 'left-col', id: 'resource-index-main-content', [
+        const LearningResourceFilters(),
+        section(classes: 'card-grid', id: 'all-resources-grid', [
+          for (final item in learningResources) _ResourceCard(item),
+        ]),
+      ]),
+      const LearningResourceFiltersSidebar(),
+    ]);
+  }
+}
+
+final class _ResourceCard extends StatelessComponent {
+  const _ResourceCard(this.resource);
+
+  final LearningResource resource;
+
+  @override
+  Component build(BuildContext context) {
+    return a(
+      id: resource.name,
+      classes: 'card outlined-card',
+      href: resource.link?.url ?? '#',
+      target: Target.blank,
+      attributes: {
+        'data-type': resource.type,
+        'data-tags': resource.tags.join(', '),
+        'data-description': resource.description,
+      },
+      [
+        if (resource.imageUrl case final imageUrl?)
+          div(classes: 'card-image-holder-material-3', [
+            img(src: imageUrl, alt: ''),
+          ]),
+        div(classes: 'card-leading', [
+          span(
+            classes: [
+              'pill-sm',
+              switch (resource.type) {
+                'codelab' || 'workshop' => 'flutter-blue',
+                'quickstart' || 'demo' => 'purple',
+                _ => 'teal',
+              },
+            ].toClasses,
+            [
+              text(
+                resource.type.substring(0, 1).toUpperCase() +
+                    resource.type.substring(1),
+              ),
+            ],
+          ),
+          _iconForLabel(resource.link?.label ?? ''),
+        ]),
+        div(classes: 'card-header', [
+          span(classes: 'card-title', [
+            text(resource.name),
+          ]),
+        ]),
+        div(classes: 'card-content', [
+          text(resource.description),
+        ]),
+      ],
+    );
+  }
+
+  Component _iconForLabel(String label) => switch (label) {
+    'Flutter GitHub' => svg(
+      classes: 'monochrome-icon',
+      width: 24.px,
+      height: 24.px,
+      [
+        const Component.element(
+          tag: 'use',
+          attributes: {'href': '/assets/images/social/github.svg#github'},
+        ),
+      ],
+    ),
+    'Dart GitHub' || 'Dart docs' => img(
+      src: '/assets/images/branding/dart/logo.svg',
+      width: 24,
+      alt: 'Dart logo',
+    ),
+    'Google Codelab' => svg(width: 24.px, height: 24.px, [
+      const Component.element(
+        tag: 'use',
+        attributes: {
+          'href':
+              '/assets/images/social/google-developers.svg#google-developers',
+        },
+      ),
+    ]),
+    'YouTube' => svg(
+      attributes: {'style': 'color: red'},
+      width: 24.px,
+      height: 24.px,
+      [
+        const Component.element(
+          tag: 'use',
+          attributes: {'href': '/assets/images/social/youtube.svg#youtube'},
+        ),
+      ],
+    ),
+    'Medium' => svg(classes: 'monochrome-icon', width: 24.px, height: 24.px, [
+      const Component.element(
+        tag: 'use',
+        attributes: {'href': '/assets/images/social/medium.svg#medium'},
+      ),
+    ]),
+    'Flutter docs' || _ => img(
+      src: '/assets/images/branding/flutter/icon/1080.png',
+      alt: 'Flutter logo',
+      width: 24,
+    ),
+  };
+}
diff --git a/site/lib/src/components/util/global_event_listener.dart b/site/lib/src/components/util/global_event_listener.dart
new file mode 100644
index 00000000000..d761217ee7f
--- /dev/null
+++ b/site/lib/src/components/util/global_event_listener.dart
@@ -0,0 +1,52 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:jaspr/jaspr.dart';
+import 'package:universal_web/web.dart' as web;
+
+final class GlobalEventListener extends StatefulComponent {
+  const GlobalEventListener(this.child, {this.onClick, this.onKeyDown});
+
+  final Component child;
+  final void Function(web.MouseEvent)? onClick;
+  final void Function(web.KeyboardEvent)? onKeyDown;
+
+  @override
+  State createState() => _GlobalClickListenerState();
+}
+
+class _GlobalClickListenerState extends State {
+  StreamSubscription? _clickSubscription;
+  StreamSubscription? _keyDownSubscription;
+
+  @override
+  void initState() {
+    super.initState();
+
+    if (kIsWeb) {
+      if (component.onClick case final onClick?) {
+        _clickSubscription = web.EventStreamProviders.clickEvent
+            .forTarget(web.document)
+            .listen(onClick);
+      }
+      if (component.onKeyDown case final onKeyDown?) {
+        _keyDownSubscription = web.EventStreamProviders.keyDownEvent
+            .forTarget(web.document)
+            .listen(onKeyDown);
+      }
+    }
+  }
+
+  @override
+  void dispose() {
+    unawaited(_clickSubscription?.cancel());
+    unawaited(_keyDownSubscription?.cancel());
+    super.dispose();
+  }
+
+  @override
+  Component build(BuildContext _) => component.child;
+}
diff --git a/site/lib/src/extensions/attribute_processor.dart b/site/lib/src/extensions/attribute_processor.dart
new file mode 100644
index 00000000000..2b5b4419112
--- /dev/null
+++ b/site/lib/src/extensions/attribute_processor.dart
@@ -0,0 +1,80 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../markdown/attribute_syntax.dart';
+
+/// A node-processing, page extension for Jaspr Content that looks for
+/// attribute markers from [AttributeBlockSyntax] and [AttributeInlineSyntax],
+/// to remove them and transfer their configured attributes.
+class AttributeProcessor implements PageExtension {
+  const AttributeProcessor();
+
+  @override
+  Future> apply(Page page, List nodes) async {
+    return _processNodes(nodes);
+  }
+
+  List _processNodes(List nodes) {
+    final processedNodes = [];
+
+    for (var i = 0; i < nodes.length; i++) {
+      final node = nodes[i];
+
+      if (node is ElementNode && node.tag == 'attribute-marker') {
+        // Found an attribute marker,
+        // apply its attributes to the previous element.
+        if (i > 0 && processedNodes.isNotEmpty) {
+          final previousIndex = processedNodes.length - 1;
+          final previousNode = processedNodes[previousIndex];
+          if (previousNode is ElementNode) {
+            processedNodes[previousIndex] = _applyAttributesToElement(
+              previousNode,
+              node.attributes,
+            );
+          }
+        }
+        // Skip adding this marker to processed nodes (effectively removing it).
+        continue;
+      } else if (node is ElementNode) {
+        final nodeChildren = node.children;
+        final processedChildren = nodeChildren != null
+            ? _processNodes(nodeChildren)
+            : null;
+        processedNodes.add(
+          ElementNode(node.tag, node.attributes, processedChildren),
+        );
+      } else {
+        processedNodes.add(node);
+      }
+    }
+
+    return processedNodes;
+  }
+
+  ElementNode _applyAttributesToElement(
+    ElementNode element,
+    Map attributes,
+  ) {
+    final newAttributes = Map.of(element.attributes);
+
+    for (final entry in attributes.entries) {
+      if (entry.key == 'class') {
+        final existingClass = newAttributes['class'];
+        if (existingClass != null && existingClass.isNotEmpty) {
+          newAttributes['class'] = '$existingClass ${entry.value}';
+        } else {
+          newAttributes['class'] = entry.value;
+        }
+      } else {
+        // For other attributes (such as id),
+        // set them directly.
+        newAttributes[entry.key] = entry.value;
+      }
+    }
+
+    return ElementNode(element.tag, newAttributes, element.children);
+  }
+}
diff --git a/site/lib/src/extensions/code_block_processor.dart b/site/lib/src/extensions/code_block_processor.dart
new file mode 100644
index 00000000000..e58953a1382
--- /dev/null
+++ b/site/lib/src/extensions/code_block_processor.dart
@@ -0,0 +1,580 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert' show LineSplitter;
+
+import 'package:collection/collection.dart';
+import 'package:jaspr/jaspr.dart' as jaspr;
+import 'package:jaspr_content/jaspr_content.dart';
+import 'package:meta/meta.dart';
+import 'package:opal/opal.dart' as opal;
+
+import '../components/common/wrapped_code_block.dart';
+import '../components/dartpad/dartpad_injector.dart';
+import '../highlight/theme/dark.dart';
+import '../highlight/theme/light.dart';
+import '../highlight/token_renderer.dart' as highlighter;
+
+final class CodeBlockProcessor implements PageExtension {
+  static final opal.LanguageRegistry _languageRegistry =
+      opal.LanguageRegistry.withDefaults();
+
+  const CodeBlockProcessor();
+
+  @override
+  Future> apply(Page page, List nodes) async {
+    return _processNodes(nodes);
+  }
+
+  List _processNodes(List nodes) {
+    return [for (final node in nodes) _processNode(node)];
+  }
+
+  Node _processNode(Node node) {
+    if (node is! ElementNode) return node;
+
+    if (node.tag.toLowerCase() == 'pre') {
+      final children = node.children;
+      if (children != null && children.isNotEmpty) {
+        final firstChild = children.first;
+        if (firstChild is ElementNode && firstChild.tag == 'code') {
+          final lines = _extractContent(firstChild);
+          final language = _extractLanguage(
+            firstChild.attributes['class'] ?? '',
+          );
+
+          final rawMetadata = firstChild.attributes.remove('data-meta');
+          final metadata = rawMetadata != null
+              ? _parseAttributes(rawMetadata)
+              : const {};
+          final title = metadata['title'];
+
+          if (language == 'dartpad') {
+            return ComponentNode(
+              DartPadWrapper(
+                content: lines.join('\n'),
+                title: title ?? 'Runnable Flutter example',
+                theme: metadata['theme'],
+                height: metadata['height'],
+                runAutomatically: metadata['run'] == 'true',
+              ),
+            );
+          }
+
+          final tag = metadata['tag'];
+
+          final rawHighlightLines = metadata['highlightLines'];
+          final skipHighlighting = metadata.containsKey('noHighlight');
+
+          var showLineNumbers = false;
+          int? initialLineNumber;
+          if (metadata.containsKey('showLineNumbers')) {
+            showLineNumbers = true;
+
+            final rawShowLineNumbers = metadata['showLineNumbers'];
+            if (rawShowLineNumbers != null) {
+              initialLineNumber = int.tryParse(rawShowLineNumbers);
+            } else {
+              initialLineNumber = 1;
+            }
+          }
+
+          final isDiff = metadata.containsKey('diff');
+          if (isDiff && showLineNumbers) {
+            throw ArgumentError(
+              'showLineNumbers and diff are not supported on the same '
+              'code block yet.',
+            );
+          }
+
+          final diffResult = isDiff ? _processDiffLines(lines) : null;
+          final linesWithDiffRemoved = diffResult?.lines ?? lines;
+          final addedLines = diffResult?.addedLines ?? const {};
+          final removedLines = diffResult?.removedLines ?? const {};
+
+          final codeLines = _removeHighlights(
+            linesWithDiffRemoved,
+            skipHighlighting,
+          );
+          final processedContent = _highlightCode(
+            codeLines,
+            language: language,
+            skipSyntaxHighlighting: skipHighlighting,
+          );
+
+          return ComponentNode(
+            WrappedCodeBlock(
+              content: processedContent,
+              textToCopy: codeLines.copyContent,
+              language: language,
+              languagesToHide: const {
+                'plaintext',
+                'text',
+                'console',
+                'ps',
+                'diff',
+              },
+              title: title,
+              highlightLines: _parseNumbersAndRanges(rawHighlightLines),
+              addedLines: addedLines,
+              removedLines: removedLines,
+              tag: tag != null ? CodeBlockTag.parse(tag) : null,
+              initialLineNumber: initialLineNumber ?? 1,
+              showLineNumbers: showLineNumbers,
+            ),
+          );
+        }
+      }
+    }
+
+    final nodeChildren = node.children;
+    return ElementNode(
+      node.tag,
+      node.attributes,
+      nodeChildren != null ? _processNodes(nodeChildren) : null,
+    );
+  }
+
+  List> _highlightCode(
+    List<_CodeLine> codeLines, {
+    required String language,
+    bool skipSyntaxHighlighting = false,
+  }) {
+    final content = codeLines.map((line) => line.content).toList();
+    final languageHighlighter = switch (_languageRegistry[language]) {
+      final highlighter? when !skipSyntaxHighlighting => highlighter,
+      _ => opal.BuiltInLanguages.text,
+    };
+    final highlightedSpans = languageHighlighter.tokenize(content);
+    final renderedSpans = highlighter.ThemedSpanRenderer(
+      themeByName: {
+        'light': highlighter.SyntaxHighlightingTheme(dashLightTheme),
+        'dark': highlighter.SyntaxHighlightingTheme(dashDarkTheme),
+      },
+    ).render(highlightedSpans);
+
+    return [
+      for (var i = 0; i < renderedSpans.length; i++)
+        _processLine(renderedSpans[i], codeLines[i].highlights),
+    ];
+  }
+
+  List _processLine(
+    List spans,
+    List<({int startColumn, int length})> highlights,
+  ) {
+    if (highlights.isEmpty) {
+      return spans.map(_createSpan).toList(growable: false);
+    }
+
+    final processedSpans = [];
+    var currentColumn = 0;
+
+    for (final span in spans) {
+      final spanEnd = currentColumn + span.content.length;
+      final intersecting = _findIntersectingHighlights(
+        highlights,
+        currentColumn,
+        spanEnd,
+      );
+
+      if (intersecting.isEmpty) {
+        processedSpans.add(_createSpan(span));
+      } else {
+        processedSpans.addAll(
+          _splitSpanByHighlights(span, intersecting, currentColumn),
+        );
+      }
+      currentColumn = spanEnd;
+    }
+
+    return processedSpans;
+  }
+
+  List<({int startColumn, int length})> _findIntersectingHighlights(
+    List<({int startColumn, int length})> highlights,
+    int spanStart,
+    int spanEnd,
+  ) => highlights
+      .where((h) {
+        final highlightEnd = h.startColumn + h.length;
+        return !(spanStart >= highlightEnd || spanEnd <= h.startColumn);
+      })
+      .sorted((a, b) => a.startColumn.compareTo(b.startColumn));
+
+  List _splitSpanByHighlights(
+    highlighter.ThemedSpan span,
+    List<({int startColumn, int length})> highlights,
+    int spanStart,
+  ) {
+    final result = [];
+    final spanLength = span.content.length;
+    var processedStart = 0;
+
+    for (final highlight in highlights) {
+      final highlightEnd = highlight.startColumn + highlight.length;
+      final startInSpan = (highlight.startColumn - spanStart).clamp(
+        0,
+        spanLength,
+      );
+      final endInSpan = (highlightEnd - spanStart).clamp(0, spanLength);
+
+      // Add non-highlighted portion before the highlight.
+      if (processedStart < startInSpan) {
+        result.add(
+          _createSpan(
+            span,
+            content: span.content.substring(processedStart, startInSpan),
+          ),
+        );
+      }
+
+      // Add highlighted portion.
+      if (startInSpan < endInSpan) {
+        result.add(
+          jaspr.Component.element(
+            tag: 'mark',
+            attributes: const {'class': 'highlight'},
+            children: [
+              _createSpan(
+                span,
+                content: span.content.substring(startInSpan, endInSpan),
+              ),
+            ],
+          ),
+        );
+        processedStart = endInSpan;
+      }
+    }
+
+    // Add remaining non-highlighted portion.
+    if (processedStart < spanLength) {
+      result.add(
+        _createSpan(
+          span,
+          content: span.content.substring(processedStart),
+        ),
+      );
+    }
+
+    return result;
+  }
+
+  jaspr.Component _createSpan(
+    highlighter.ThemedSpan span, {
+    String? content,
+  }) {
+    return jaspr.span(
+      [jaspr.text(content ?? span.content)],
+      attributes: {
+        'style': ?span.toInlineStyle(defaultTheme: 'light'),
+      },
+    );
+  }
+
+  String _extractLanguage(String className) {
+    final match = RegExp(r'language-(\w+)').firstMatch(className);
+    return match?.group(1)?.toLowerCase() ?? 'plaintext';
+  }
+
+  List _extractContent(Node node) {
+    // Remove trailing empty spaces and new lines.
+    final text = node.innerText.trimRight();
+
+    return const LineSplitter()
+        .convert(text)
+        .map((l) => l.trimRight())
+        .toList(growable: false);
+  }
+
+  List<_CodeLine> _removeHighlights(
+    List lines, [
+    bool skipHighlighting = false,
+  ]) {
+    if (skipHighlighting) {
+      return lines
+          .map((line) => _CodeLine(content: line, highlights: const []))
+          .toList(growable: false);
+    }
+
+    final lineHighlights = >{};
+    ({int startLine, int startColumn})? currentHighlight;
+
+    final processedLines = [];
+
+    for (var lineIndex = 0; lineIndex < lines.length; lineIndex++) {
+      final line = lines[lineIndex];
+      if (line.trim().isEmpty) {
+        // Empty lines should still be a part of the output.
+        processedLines.add('');
+        continue;
+      }
+
+      final processedLine = StringBuffer();
+      var i = 0;
+
+      while (i < line.length) {
+        // Check for the opening marker [!.
+        if (i + 1 < line.length && line[i] == '[' && line[i + 1] == '!') {
+          if (currentHighlight != null) {
+            throw ArgumentError(
+              'Opening highlight marker "[!" found at '
+              'line ${lineIndex + 1}, column ${i + 1} while '
+              'previous highlight at line ${currentHighlight.startLine + 1}, '
+              'column ${currentHighlight.startColumn + 1} is not closed',
+            );
+          }
+          currentHighlight = (
+            startLine: lineIndex,
+            startColumn: processedLine.length,
+          );
+
+          // Skip past the [! marker in the line.
+          i += 2;
+          continue;
+        }
+
+        // If there's an open highlight span, check for the closing marker !].
+        if (currentHighlight != null &&
+            i + 1 < line.length &&
+            line[i] == '!' &&
+            line[i + 1] == ']') {
+          if (currentHighlight.startLine == lineIndex) {
+            // If the highlight span is opened and closed in the same line.
+            lineHighlights.putIfAbsent(lineIndex, () => []).add((
+              startColumn: currentHighlight.startColumn,
+              length: processedLine.length - currentHighlight.startColumn,
+            ));
+          } else {
+            // If the highlight span is opened then closed in separate lines.
+
+            // Add the highlight range for the line the span is opened in.
+            lineHighlights
+                .putIfAbsent(currentHighlight.startLine, () => [])
+                .add((
+                  startColumn: currentHighlight.startColumn,
+                  length:
+                      processedLines[currentHighlight.startLine].length -
+                      currentHighlight.startColumn,
+                ));
+
+            // Add the highlight range for the lines completely included.
+            for (var j = currentHighlight.startLine + 1; j < lineIndex; j++) {
+              lineHighlights.putIfAbsent(j, () => []).add((
+                startColumn: 0,
+                length: processedLines[j].length,
+              ));
+            }
+
+            // Add the highlight range for the line the span is closed in.
+            lineHighlights.putIfAbsent(lineIndex, () => []).add((
+              startColumn: 0,
+              length: processedLine.length,
+            ));
+          }
+
+          currentHighlight = null;
+
+          // Skip past the !] marker in the line.
+          i += 2;
+          continue;
+        }
+
+        processedLine.write(line[i]);
+        i++;
+      }
+
+      processedLines.add(processedLine.toString());
+    }
+
+    // Check if a highlight span was never closed.
+    if (currentHighlight != null) {
+      throw ArgumentError(
+        'Unclosed highlight marker starting at '
+        'line ${currentHighlight.startLine + 1}, '
+        'column ${currentHighlight.startColumn + 1}',
+      );
+    }
+
+    return [
+      for (var i = 0; i < processedLines.length; i++)
+        _CodeLine(
+          content: processedLines[i],
+          highlights: lineHighlights[i] ?? [],
+        ),
+    ];
+  }
+
+  /// Processes lines for diff mode, extracting added/removed line markers.
+  ///
+  /// Lines starting with '+' are marked as added lines.
+  /// Lines starting with '-' are marked as removed lines.
+  /// The first two characters (marker and space) are removed from each line.
+  ({
+    List lines,
+    Set addedLines,
+    Set removedLines,
+  })
+  _processDiffLines(List lines) {
+    final addedLines = {};
+    final removedLines = {};
+    final processedLines = [];
+
+    for (var lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
+      final line = lines[lineIndex];
+
+      switch (line.isNotEmpty ? line[0] : '') {
+        case '+':
+          addedLines.add(lineIndex + 1);
+        case '-':
+          removedLines.add(lineIndex + 1);
+      }
+
+      // Remove the first 2 characters (marker and space).
+      processedLines.add(line.length >= 2 ? line.substring(2) : '');
+    }
+
+    return (
+      lines: processedLines,
+      addedLines: addedLines,
+      removedLines: removedLines,
+    );
+  }
+}
+
+@immutable
+final class _CodeLine {
+  final String content;
+  final List<({int startColumn, int length})> highlights;
+
+  const _CodeLine({required this.content, required this.highlights});
+}
+
+extension on List<_CodeLine> {
+  static final RegExp _terminalReplacementPattern = RegExp(
+    r'^(\s*\$\s*)|(PS\s+)?(C:\\(.*)>\s*)',
+    multiLine: true,
+  );
+  static final RegExp _zeroWidthSpaceReplacementPattern = RegExp(r'\u200B');
+
+  String get copyContent => map((line) => line.content)
+      .join('\n')
+      .replaceAll(_terminalReplacementPattern, '')
+      .replaceAll(_zeroWidthSpaceReplacementPattern, '');
+}
+
+/// Parses a comma-separated list of numbers and ranges into a set of numbers.
+///
+/// Returns all unique numbers specified in the input.
+Set _parseNumbersAndRanges(String? input) {
+  if (input == null) return const {};
+  final elements = input.trim().split(',');
+  if (elements.isEmpty) return const {};
+
+  final combinedNumbers = {};
+
+  for (final element in elements) {
+    final rangeParts = element.split('-');
+
+    // If it includes a dash, it is (hopefully) a range between two numbers.
+    if (rangeParts.length > 1) {
+      // Split by the dash, and turn each string into a number.
+      // Assume the user only included one dash.
+      final start = int.tryParse(rangeParts[0].trim());
+      final end = int.tryParse(rangeParts[1].trim());
+
+      if (start != null && end != null) {
+        for (var i = start; i <= end; i++) {
+          combinedNumbers.add(i);
+        }
+      }
+    } else {
+      // It's (hopefully) just a single number.
+      final number = int.tryParse(element.trim());
+      if (number != null) {
+        combinedNumbers.add(number);
+      }
+    }
+  }
+
+  return combinedNumbers;
+}
+
+/// Matches a key-value attribute pair, similar to HTML elements.
+///
+/// Group 1: The attribute key.
+/// Group 2: The value if quoted and present.
+/// Group 3: The value if unquoted and present.
+final RegExp _attributeRegex = RegExp(r'(\w+)(?:=(?:"([^"]*)"|(\S+)))?');
+
+Map _parseAttributes(String input) {
+  final matches = _attributeRegex.allMatches(input);
+
+  return {
+    for (final match in matches)
+      match.group(1)!: match.group(2) ?? match.group(3),
+  };
+}
+
+extension ThemedSpanToHtml on highlighter.ThemedSpan {
+  String? toInlineStyle({String? defaultTheme}) {
+    final buffer = StringBuffer();
+
+    for (final MapEntry(key: themeName, value: style) in styleByTheme.entries) {
+      final isDefault = themeName == defaultTheme;
+
+      if (style.foregroundColor case final fgColor?) {
+        if (isDefault) {
+          buffer.write('color: rgba(');
+          buffer.write((fgColor.red * 255).round());
+          buffer.write(', ');
+          buffer.write((fgColor.green * 255).round());
+          buffer.write(', ');
+          buffer.write((fgColor.blue * 255).round());
+          buffer.write(', ');
+          buffer.write(fgColor.alpha);
+          buffer.write('); ');
+        } else {
+          buffer.write('--opal-$themeName-color: rgba(');
+          buffer.write((fgColor.red * 255).round());
+          buffer.write(', ');
+          buffer.write((fgColor.green * 255).round());
+          buffer.write(', ');
+          buffer.write((fgColor.blue * 255).round());
+          buffer.write(', ');
+          buffer.write(fgColor.alpha);
+          buffer.write('); ');
+        }
+      }
+
+      if (style.fontStyle case final fontStyle?) {
+        final fontStyleValue = switch (fontStyle) {
+          highlighter.FontStyle.italic => 'italic',
+          highlighter.FontStyle.normal => 'normal',
+        };
+
+        if (isDefault) {
+          buffer.write('font-style: $fontStyleValue; ');
+        } else {
+          buffer.write('--opal-$themeName-font-style: $fontStyleValue; ');
+        }
+      }
+
+      if (style.fontWeight case final fontWeight?) {
+        if (isDefault) {
+          buffer.write('font-weight: ${fontWeight.weight}; ');
+        } else {
+          buffer.write('--opal-$themeName-font-weight: ${fontWeight.weight}; ');
+        }
+      }
+    }
+
+    final resultingStyle = buffer.toString().trimRight();
+    if (resultingStyle.isEmpty) {
+      return null;
+    }
+
+    return resultingStyle;
+  }
+}
diff --git a/site/lib/src/extensions/header_extractor.dart b/site/lib/src/extensions/header_extractor.dart
new file mode 100644
index 00000000000..7b7b9623f36
--- /dev/null
+++ b/site/lib/src/extensions/header_extractor.dart
@@ -0,0 +1,60 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr_content/jaspr_content.dart';
+import 'package:meta/meta.dart';
+
+final class HeaderExtractorExtension implements PageExtension {
+  const HeaderExtractorExtension();
+
+  @override
+  Future> apply(Page page, List nodes) async {
+    page.apply(data: {'contentHeaders': _extractHeaders(nodes)});
+
+    return nodes;
+  }
+
+  List _extractHeaders(List nodes) {
+    final headers = [];
+
+    for (final node in nodes) {
+      if (node is ElementNode) {
+        final tagName = node.tag.toLowerCase();
+
+        if (tagName.startsWith('h')) {
+          // Verify this is a header element with a valid level.
+          final level = int.tryParse(tagName.substring(1));
+          if (level != null && level >= 1 && level <= 6) {
+            headers.add(
+              ContentHeader(
+                text: node.innerText,
+                level: level,
+                attributes: node.attributes,
+              ),
+            );
+          }
+        }
+
+        if (node.children case final children?) {
+          headers.addAll(_extractHeaders(children));
+        }
+      }
+    }
+
+    return headers;
+  }
+}
+
+@immutable
+final class ContentHeader {
+  final String text;
+  final int level;
+  final Map attributes;
+
+  const ContentHeader({
+    required this.text,
+    required this.level,
+    this.attributes = const {},
+  });
+}
diff --git a/site/lib/src/extensions/header_processor.dart b/site/lib/src/extensions/header_processor.dart
new file mode 100644
index 00000000000..2e322f4fb88
--- /dev/null
+++ b/site/lib/src/extensions/header_processor.dart
@@ -0,0 +1,71 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr_content/jaspr_content.dart';
+
+/// A node-processing, page extension for Jaspr Content that
+/// wraps each `h1` -> `h5` element in a div with the `header-wrapper` class
+/// and adds an anchor that can clicked and linked to.
+final class HeaderWrapperExtension implements PageExtension {
+  const HeaderWrapperExtension();
+
+  @override
+  Future> apply(Page page, List nodes) async {
+    final usedIds = {};
+    return _processNodes(nodes, usedIds);
+  }
+
+  List _processNodes(List nodes, Set usedIds) {
+    return [for (final node in nodes) _processNode(node, usedIds)];
+  }
+
+  Node _processNode(Node node, Set usedIds) {
+    if (node is! ElementNode) return node;
+
+    final tagName = node.tag.toLowerCase();
+    if (!const {'h2', 'h3', 'h4', 'h5'}.contains(tagName)) {
+      // If it's not any of the supported heading levels,
+      // recurse into its children.
+      final nodeChildren = node.children;
+      return ElementNode(
+        node.tag,
+        node.attributes,
+        nodeChildren != null ? _processNodes(nodeChildren, usedIds) : null,
+      );
+    }
+
+    final rawHeaderId = node.attributes['id'];
+    if (rawHeaderId == null) return node;
+
+    // Account for headers with the same base id,
+    // appending a dash and an integer until the header has a unique id.
+    var headerId = rawHeaderId;
+    for (var i = 1; usedIds.contains(headerId); i += 1) {
+      headerId = '$rawHeaderId-$i';
+    }
+    usedIds.add(headerId);
+
+    // Update header ID to be the unique one as well.
+    node.attributes['id'] = headerId;
+
+    final headerText = node.innerText;
+
+    return ElementNode(
+      'div',
+      {'class': 'header-wrapper'},
+      [
+        node,
+        ElementNode(
+          'a',
+          {
+            'class': 'heading-link',
+            'href': '#$headerId',
+            'aria-label': "Link to '$headerText' section",
+          },
+          const [TextNode('#')],
+        ),
+      ],
+    );
+  }
+}
diff --git a/site/lib/src/extensions/registry.dart b/site/lib/src/extensions/registry.dart
new file mode 100644
index 00000000000..0439d23d944
--- /dev/null
+++ b/site/lib/src/extensions/registry.dart
@@ -0,0 +1,21 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr_content/jaspr_content.dart';
+
+import 'attribute_processor.dart';
+import 'code_block_processor.dart';
+import 'header_extractor.dart';
+import 'header_processor.dart';
+import 'table_processor.dart';
+
+/// A list of all node-processing, page extensions to applied to
+/// content loaded with Jaspr Content.
+const List allNodeProcessingExtensions = [
+  AttributeProcessor(),
+  HeaderExtractorExtension(),
+  HeaderWrapperExtension(),
+  TableWrapperExtension(),
+  CodeBlockProcessor(),
+];
diff --git a/site/lib/src/extensions/table_processor.dart b/site/lib/src/extensions/table_processor.dart
new file mode 100644
index 00000000000..f768a580894
--- /dev/null
+++ b/site/lib/src/extensions/table_processor.dart
@@ -0,0 +1,73 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr_content/jaspr_content.dart';
+
+/// A node-processing, page extension for Jaspr Content that
+/// wraps each `` element in a div with the `table-wrapper` class to
+/// enable improved styling and horizontal scrolling.
+final class TableWrapperExtension implements PageExtension {
+  const TableWrapperExtension();
+
+  @override
+  Future> apply(Page page, List nodes) async {
+    return _processNodes(nodes, isRoot: true);
+  }
+
+  List _processNodes(List nodes, {bool isRoot = false}) {
+    final processedNodes = [];
+
+    for (var i = 0; i < nodes.length; i++) {
+      final node = nodes[i];
+
+      if (node is ElementNode && node.tag.toLowerCase() == 'table') {
+        // Check if the previous node was a div with table-wrapper class
+        // (only check at root level to avoid issues with nested structures).
+        if (isRoot && i > 0) {
+          final prevNode = processedNodes.last;
+          if (prevNode is ElementNode &&
+              prevNode.tag.toLowerCase() == 'div' &&
+              (prevNode.attributes['class'] ?? '').contains('table-wrapper')) {
+            // This table is already wrapped, skip wrapping.
+            processedNodes.add(_processNode(node));
+            continue;
+          }
+        }
+
+        // Wrap the table.
+        processedNodes.add(
+          ElementNode('div', {'class': 'table-wrapper'}, [node]),
+        );
+      } else {
+        processedNodes.add(_processNode(node));
+      }
+    }
+
+    return processedNodes;
+  }
+
+  Node _processNode(Node node) {
+    if (node is! ElementNode) return node;
+
+    final tagName = node.tag.toLowerCase();
+
+    // Don't process table elements here as they're handled in _processNodes.
+    if (tagName == 'table') return node;
+
+    // Check if this is already a table-wrapper div.
+    if (tagName == 'div' &&
+        (node.attributes['class'] ?? '').contains('table-wrapper')) {
+      // Don't recurse into table-wrapper divs to avoid double wrapping.
+      return node;
+    }
+
+    // Recurse into children for other elements.
+    final nodeChildren = node.children;
+    return ElementNode(
+      node.tag,
+      node.attributes,
+      nodeChildren != null ? _processNodes(nodeChildren) : null,
+    );
+  }
+}
diff --git a/site/lib/src/highlight/theme/dark.dart b/site/lib/src/highlight/theme/dark.dart
new file mode 100644
index 00000000000..ad534a9f1f1
--- /dev/null
+++ b/site/lib/src/highlight/theme/dark.dart
@@ -0,0 +1,381 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:opal/opal.dart' show MarkupTags, Tag, Tags;
+
+import '../token_renderer.dart';
+
+/// The syntax highlighting for code blocks in dark mode.
+final Map dashDarkTheme = {
+  Tags.comment: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x8B,
+      green: 0x95,
+      blue: 0xA7,
+    ),
+  ),
+  Tags.lineComment: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x8B,
+      green: 0x95,
+      blue: 0xA7,
+    ),
+  ),
+  Tags.blockComment: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x8B,
+      green: 0x95,
+      blue: 0xA7,
+    ),
+  ),
+  Tags.docComment: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x8B,
+      green: 0x95,
+      blue: 0xA7,
+    ),
+  ),
+
+  Tags.keyword: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xFF,
+      green: 0x89,
+      blue: 0x7E,
+    ),
+  ),
+  Tags.declarationKeyword: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xFF,
+      green: 0x89,
+      blue: 0x7E,
+    ),
+  ),
+  Tags.modifierKeyword: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xFF,
+      green: 0x89,
+      blue: 0x7E,
+    ),
+  ),
+  Tags.controlKeyword: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xFF,
+      green: 0x89,
+      blue: 0x7E,
+    ),
+  ),
+  const Tag('name', parent: Tags.preprocessorDirective): const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xFF,
+      green: 0x89,
+      blue: 0x7E,
+    ),
+  ),
+
+  Tags.operator: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xE1,
+      green: 0xE2,
+      blue: 0xEC,
+    ),
+  ),
+
+  Tags.stringLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.stringContent: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.quotedString: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.singleQuoteString: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.doubleQuoteString: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.tripleQuoteString: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.characterLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+
+  Tags.numberLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.integerLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.floatLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+
+  Tags.booleanLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.trueLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.falseLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  Tags.nullLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+
+  Tags.function: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xB5,
+      green: 0x81,
+      blue: 0xFF,
+    ),
+  ),
+  Tags.constructor: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xB5,
+      green: 0x81,
+      blue: 0xFF,
+    ),
+  ),
+  Tags.property: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xB5,
+      green: 0x81,
+      blue: 0xFF,
+    ),
+  ),
+
+  Tags.type: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x6B,
+      green: 0xB1,
+      blue: 0xFF,
+    ),
+  ),
+  Tags.builtInType: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x6B,
+      green: 0xB1,
+      blue: 0xFF,
+    ),
+  ),
+  Tags.tag: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x6B,
+      green: 0xB1,
+      blue: 0xFF,
+    ),
+  ),
+
+  Tags.variable: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xE1,
+      green: 0xE2,
+      blue: 0xEC,
+    ),
+  ),
+  Tags.parameter: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xE1,
+      green: 0xE2,
+      blue: 0xEC,
+    ),
+  ),
+
+  Tags.punctuation: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xDC,
+      green: 0xDC,
+      blue: 0xDC,
+    ),
+  ),
+  Tags.separator: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xDC,
+      green: 0xDC,
+      blue: 0xDC,
+    ),
+  ),
+  Tags.accessor: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xDC,
+      green: 0xDC,
+      blue: 0xDC,
+    ),
+  ),
+
+  Tags.annotation: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xB5,
+      green: 0x81,
+      blue: 0xFF,
+    ),
+  ),
+
+  Tags.specialIdentifier: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xFF,
+      green: 0x89,
+      blue: 0x7E,
+    ),
+  ),
+
+  Tags.stringEscape: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x2A,
+      green: 0xF5,
+      blue: 0xDE,
+    ),
+    fontWeight: FontWeight.w600,
+  ),
+
+  Tags.stringInterpolation: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xE1,
+      green: 0xE2,
+      blue: 0xEC,
+    ),
+  ),
+
+  MarkupTags.bold: const TextStyle(
+    fontWeight: FontWeight.w700,
+  ),
+  MarkupTags.italic: const TextStyle(
+    fontStyle: FontStyle.italic,
+  ),
+  MarkupTags.underline: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xDC,
+      green: 0xDC,
+      blue: 0xDC,
+    ),
+  ),
+  MarkupTags.strikethrough: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x8B,
+      green: 0x95,
+      blue: 0xA7,
+    ),
+  ),
+  MarkupTags.heading: const TextStyle(
+    fontWeight: FontWeight.w700,
+  ),
+  MarkupTags.code: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  MarkupTags.codeBlock: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xDC,
+      green: 0xDC,
+      blue: 0xDC,
+    ),
+  ),
+  MarkupTags.link: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x6B,
+      green: 0xB1,
+      blue: 0xFF,
+    ),
+  ),
+  MarkupTags.linkReference: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x6B,
+      green: 0xB1,
+      blue: 0xFF,
+    ),
+  ),
+  MarkupTags.linkDefinition: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x6B,
+      green: 0xB1,
+      blue: 0xFF,
+    ),
+  ),
+
+  MarkupTags.inserted: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x1C,
+      green: 0xDA,
+      blue: 0xC5,
+    ),
+  ),
+  MarkupTags.removed: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xFF,
+      green: 0x89,
+      blue: 0x7E,
+    ),
+  ),
+
+  Tags.invalid: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xFF,
+      green: 0x89,
+      blue: 0x7E,
+    ),
+    fontWeight: FontWeight.w600,
+  ),
+};
diff --git a/site/lib/src/highlight/theme/light.dart b/site/lib/src/highlight/theme/light.dart
new file mode 100644
index 00000000000..b793765e733
--- /dev/null
+++ b/site/lib/src/highlight/theme/light.dart
@@ -0,0 +1,381 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:opal/opal.dart' show MarkupTags, Tag, Tags;
+
+import '../token_renderer.dart';
+
+/// The syntax highlighting for code blocks in light mode.
+final Map dashLightTheme = {
+  Tags.comment: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x59,
+      green: 0x61,
+      blue: 0x6E,
+    ),
+  ),
+  Tags.lineComment: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x59,
+      green: 0x61,
+      blue: 0x6E,
+    ),
+  ),
+  Tags.blockComment: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x59,
+      green: 0x61,
+      blue: 0x6E,
+    ),
+  ),
+  Tags.docComment: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x59,
+      green: 0x61,
+      blue: 0x6E,
+    ),
+  ),
+
+  Tags.keyword: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xBD,
+      green: 0x23,
+      blue: 0x14,
+    ),
+  ),
+  Tags.declarationKeyword: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xBD,
+      green: 0x23,
+      blue: 0x14,
+    ),
+  ),
+  Tags.modifierKeyword: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xBD,
+      green: 0x23,
+      blue: 0x14,
+    ),
+  ),
+  Tags.controlKeyword: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xBD,
+      green: 0x23,
+      blue: 0x14,
+    ),
+  ),
+  const Tag('name', parent: Tags.preprocessorDirective): const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xBD,
+      green: 0x23,
+      blue: 0x14,
+    ),
+  ),
+
+  Tags.operator: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x19,
+      green: 0x1C,
+      blue: 0x22,
+    ),
+  ),
+
+  Tags.stringLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.stringContent: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.quotedString: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.singleQuoteString: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.doubleQuoteString: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.tripleQuoteString: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.characterLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+
+  Tags.numberLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.integerLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.floatLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+
+  Tags.booleanLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.trueLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.falseLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  Tags.nullLiteral: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+
+  Tags.function: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x62,
+      green: 0x00,
+      blue: 0xEE,
+    ),
+  ),
+  Tags.constructor: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x62,
+      green: 0x00,
+      blue: 0xEE,
+    ),
+  ),
+  Tags.property: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x62,
+      green: 0x00,
+      blue: 0xEE,
+    ),
+  ),
+
+  Tags.type: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x14,
+      green: 0x6B,
+      blue: 0xCD,
+    ),
+  ),
+  Tags.builtInType: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x14,
+      green: 0x6B,
+      blue: 0xCD,
+    ),
+  ),
+  Tags.tag: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x14,
+      green: 0x6B,
+      blue: 0xCD,
+    ),
+  ),
+
+  Tags.variable: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x19,
+      green: 0x1C,
+      blue: 0x22,
+    ),
+  ),
+  Tags.parameter: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x19,
+      green: 0x1C,
+      blue: 0x22,
+    ),
+  ),
+
+  Tags.punctuation: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x19,
+      green: 0x1C,
+      blue: 0x22,
+    ),
+  ),
+  Tags.separator: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x19,
+      green: 0x1C,
+      blue: 0x22,
+    ),
+  ),
+  Tags.accessor: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x19,
+      green: 0x1C,
+      blue: 0x22,
+    ),
+  ),
+
+  Tags.annotation: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x62,
+      green: 0x00,
+      blue: 0xEE,
+    ),
+  ),
+
+  Tags.specialIdentifier: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xBD,
+      green: 0x23,
+      blue: 0x14,
+    ),
+  ),
+
+  Tags.stringEscape: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0A,
+      green: 0x5A,
+      blue: 0x50,
+    ),
+    fontWeight: FontWeight.w600,
+  ),
+
+  Tags.stringInterpolation: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x62,
+      green: 0x00,
+      blue: 0xEE,
+    ),
+  ),
+
+  MarkupTags.bold: const TextStyle(
+    fontWeight: FontWeight.w700,
+  ),
+  MarkupTags.italic: const TextStyle(
+    fontStyle: FontStyle.italic,
+  ),
+  MarkupTags.underline: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x19,
+      green: 0x1C,
+      blue: 0x22,
+    ),
+  ),
+  MarkupTags.strikethrough: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x59,
+      green: 0x61,
+      blue: 0x6E,
+    ),
+  ),
+  MarkupTags.heading: const TextStyle(
+    fontWeight: FontWeight.w700,
+  ),
+  MarkupTags.code: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  MarkupTags.codeBlock: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x19,
+      green: 0x1C,
+      blue: 0x22,
+    ),
+  ),
+  MarkupTags.link: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x14,
+      green: 0x6B,
+      blue: 0xCD,
+    ),
+  ),
+  MarkupTags.linkReference: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x14,
+      green: 0x6B,
+      blue: 0xCD,
+    ),
+  ),
+  MarkupTags.linkDefinition: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x14,
+      green: 0x6B,
+      blue: 0xCD,
+    ),
+  ),
+
+  MarkupTags.inserted: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0x0C,
+      green: 0x70,
+      blue: 0x64,
+    ),
+  ),
+  MarkupTags.removed: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xBD,
+      green: 0x23,
+      blue: 0x14,
+    ),
+  ),
+
+  Tags.invalid: const TextStyle(
+    foregroundColor: Color.fromArgb(
+      red: 0xBD,
+      green: 0x23,
+      blue: 0x14,
+    ),
+    fontWeight: FontWeight.w600,
+  ),
+};
diff --git a/site/lib/src/highlight/token_renderer.dart b/site/lib/src/highlight/token_renderer.dart
new file mode 100644
index 00000000000..e158c57e928
--- /dev/null
+++ b/site/lib/src/highlight/token_renderer.dart
@@ -0,0 +1,160 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:meta/meta.dart';
+import 'package:opal/opal.dart' show Tag, TaggedToken;
+
+/// Renderer for converting spans of tagged tokens from `package:opal`
+/// to themed spans according to the configured themes.
+final class ThemedSpanRenderer {
+  /// Themes to be used for rendering.
+  final Map themeByName;
+  const ThemedSpanRenderer({required this.themeByName});
+
+  /// Renders the specified [tokenLines] into a themed list of spans by line.
+  /// Each top-level list represents a single line of text.
+  @useResult
+  List> render(List> tokenLines) {
+    final result = >[];
+
+    for (final line in tokenLines) {
+      final currentLine = [];
+      for (final token in line) {
+        final styleByTheme = {};
+        for (final MapEntry(key: themeName, value: theme)
+            in themeByName.entries) {
+          final style = theme.styleForSpan(token);
+          if (style != null) {
+            styleByTheme[themeName] = style;
+          }
+        }
+        currentLine.add(
+          ThemedSpan(
+            content: token.content,
+            styleByTheme: styleByTheme,
+            tag: token.tags.join(','),
+          ),
+        );
+      }
+
+      result.add(currentLine);
+    }
+
+    return result;
+  }
+}
+
+/// A theme to be used for syntax highlighting of [TaggedToken].
+final class SyntaxHighlightingTheme {
+  /// What [TextStyle] should be give for a specific [Tag].
+  final Map _textStyleByTag;
+
+  SyntaxHighlightingTheme(Map textStyleByTag)
+    : _textStyleByTag = {...textStyleByTag};
+
+  @useResult
+  TextStyle? styleForSpan(TaggedToken token) => token.tags.reversed
+      .expand((t) => t.expand())
+      .map((t) => _textStyleByTag[t])
+      .nonNulls
+      .firstOrNull;
+}
+
+final class ThemedSpan {
+  final String content;
+  final Map styleByTheme;
+  final String tag;
+
+  ThemedSpan({
+    required this.content,
+    required this.styleByTheme,
+    required this.tag,
+  });
+}
+
+final class TextStyle {
+  static const none = TextStyle();
+
+  final Color? foregroundColor;
+  final Color? backgroundColor;
+  final FontStyle? fontStyle;
+  final FontWeight? fontWeight;
+
+  const TextStyle({
+    this.foregroundColor,
+    this.backgroundColor,
+    this.fontStyle,
+    this.fontWeight,
+  });
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is TextStyle &&
+          foregroundColor == other.foregroundColor &&
+          backgroundColor == other.backgroundColor &&
+          fontStyle == other.fontStyle &&
+          fontWeight == other.fontWeight;
+
+  @override
+  int get hashCode =>
+      Object.hash(foregroundColor, backgroundColor, fontStyle, fontWeight);
+}
+
+final class Color {
+  final double alpha;
+  final double red;
+  final double green;
+  final double blue;
+
+  const Color({
+    this.alpha = 1,
+    required this.red,
+    required this.green,
+    required this.blue,
+  });
+
+  const Color.fromArgb({
+    int alpha = 0xFF,
+    required int red,
+    required int green,
+    required int blue,
+  }) : alpha = (alpha & 0xFF) / 255,
+       red = (red & 0xFF) / 255,
+       green = (green & 0xFF) / 255,
+       blue = (blue & 0xFF) / 255;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Color &&
+          alpha == other.alpha &&
+          red == other.red &&
+          green == other.green &&
+          blue == other.blue;
+
+  @override
+  int get hashCode => Object.hash(alpha, red, green, blue);
+}
+
+enum FontStyle {
+  normal,
+  italic,
+}
+
+enum FontWeight {
+  w100(100),
+  w200(200),
+  w300(300),
+  w400(400),
+  w500(500),
+  w600(600),
+  w700(700),
+  w800(800),
+  w900(900);
+
+  final int weight;
+
+  const FontWeight(this.weight);
+}
diff --git a/site/lib/src/layouts/catalog_page_layout.dart b/site/lib/src/layouts/catalog_page_layout.dart
new file mode 100644
index 00000000000..abaa511a2c7
--- /dev/null
+++ b/site/lib/src/layouts/catalog_page_layout.dart
@@ -0,0 +1,295 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../markdown/markdown_parser.dart';
+import '../util.dart';
+import 'doc_layout.dart';
+
+/// Used as the layout for the widget catalog pages.
+// TODO: This is directly converted from the original Liquid logic.
+//  We should either completely replace it with a new widget catalog
+//  or clean it up.
+final class CatalogPageLayout extends DocLayout {
+  static const String _placeholderImagePath =
+      '/assets/images/docs/catalog-widget-placeholder.png';
+
+  const CatalogPageLayout();
+
+  @override
+  String get name => 'widget-catalog-page';
+
+  @override
+  Component buildBody(Page page, Component child) {
+    final pageData = page.data.page;
+    final widgetCategory = pageData['widgetCategory'] as String;
+    final isMaterialCatalog = pageData['materialCatalog'] == true;
+
+    final catalogData = page.data['catalog'] as Map;
+    final catalogIndex = (catalogData['index'] as List)
+        .cast>();
+    final category = _CategoryInfo(
+      catalogIndex.firstWhere(
+        (c) => c['name'] == widgetCategory,
+        orElse: () => const {},
+      ),
+    );
+
+    final catalogWidgets = (catalogData['widgets'] as List)
+        .cast>();
+
+    final widgetsInCategory = catalogWidgets
+        .map(_WidgetInfo.new)
+        .where((w) => w.categories.contains(widgetCategory))
+        .toList(growable: false);
+
+    final subcategories = category.subcategories;
+
+    return super.buildBody(
+      page,
+      Component.fragment([
+        child,
+        // Only show description for non-material catalogs.
+        if (!isMaterialCatalog)
+          if (category.description case final String description
+              when description.isNotEmpty)
+            DashMarkdown(content: description),
+
+        // Only show main category widgets for non-material catalogs.
+        if (!isMaterialCatalog && widgetsInCategory.isNotEmpty)
+          _buildCardGrid(
+            widgetsInCategory,
+            isMaterialCatalog: isMaterialCatalog,
+          ),
+
+        if (subcategories.isNotEmpty) ...[
+          for (final sub in subcategories)
+            ..._buildSubcategorySection(
+              sub,
+              catalogWidgets,
+              isMaterialCatalog: isMaterialCatalog,
+            ),
+        ],
+
+        if (isMaterialCatalog)
+          p([
+            text('Find more widgets in the '),
+            a(href: '/ui/widgets/material2', [
+              text('Material 2 widget catalog'),
+            ]),
+            text(' and other categories of the '),
+            a(href: '/ui/widgets', [text('widget catalog')]),
+            text('.'),
+          ])
+        else
+          p([
+            text('Find more widgets in the '),
+            a(href: '/ui/widgets', [text('widget catalog')]),
+            text('.'),
+          ]),
+      ]),
+    );
+  }
+
+  List _buildSubcategorySection(
+    _SubcategoryInfo subcategory,
+    List> allWidgets, {
+    required bool isMaterialCatalog,
+  }) {
+    final subName = subcategory.name;
+    if (subName.isEmpty) return const [];
+
+    final widgets = allWidgets
+        .map(_WidgetInfo.new)
+        .where((w) => w.subcategories.contains(subName))
+        .toList(growable: false);
+
+    if (widgets.isEmpty) return const [];
+
+    return [
+      h2(id: slugify(subName), [text(subName)]),
+      _buildCardGrid(
+        widgets,
+        isMaterialCatalog: isMaterialCatalog,
+        subcategory: subcategory,
+      ),
+    ];
+  }
+
+  Component _buildCardGrid(
+    List<_WidgetInfo> widgets, {
+    required bool isMaterialCatalog,
+    _SubcategoryInfo? subcategory,
+  }) {
+    final gridClasses = isMaterialCatalog
+        ? 'card-grid material-cards'
+        : 'card-grid';
+
+    return div(
+      classes: gridClasses,
+      [
+        for (final widget in widgets)
+          _buildWidgetCard(
+            widget,
+            isMaterialCatalog: isMaterialCatalog,
+            subcategory: subcategory,
+          ),
+      ],
+    );
+  }
+
+  Component _buildWidgetCard(
+    _WidgetInfo widget, {
+    required bool isMaterialCatalog,
+    _SubcategoryInfo? subcategory,
+  }) {
+    return a(
+      classes: 'card outlined-card',
+      href: widget.link,
+      [
+        _buildCardImageHolder(
+          name: widget.name,
+          vector: widget.vector,
+          imageSrc: widget.imageSrc,
+          hoverBackgroundSrc: widget.hoverBackgroundSrc,
+          isMaterialCatalog: isMaterialCatalog,
+          subcategoryColor: subcategory?.color,
+        ),
+        div(
+          classes: 'card-header',
+          [
+            header(
+              classes: 'card-title',
+              [text(widget.name)],
+            ),
+          ],
+        ),
+        div(
+          classes: 'card-content',
+          [
+            DashMarkdown(
+              content: truncateWords(widget.description, 25),
+            ),
+          ],
+        ),
+      ],
+    );
+  }
+
+  Component _buildCardImageHolder({
+    required String name,
+    required String? vector,
+    required String? imageSrc,
+    required String? hoverBackgroundSrc,
+    required bool isMaterialCatalog,
+    required String? subcategoryColor,
+  }) {
+    final holderClass = isMaterialCatalog
+        ? 'card-image-holder-material-3'
+        : 'card-image-holder';
+
+    final imageAlt = isMaterialCatalog
+        ? 'Rendered example of the $name Material widget.'
+        : 'Rendered image or visualization of the $name widget.';
+
+    const placeholderAlt =
+        'Placeholder Flutter logo in place of '
+        'missing widget image or visualization.';
+
+    final styleAttributes = isMaterialCatalog && subcategoryColor != null
+        ? {'style': '--bg-color: $subcategoryColor'}
+        : {};
+
+    return div(
+      classes: holderClass,
+      attributes: styleAttributes,
+      [
+        if (isMaterialCatalog) ...[
+          // Material catalog always expects an image.
+          if (imageSrc != null && imageSrc.isNotEmpty)
+            img(alt: imageAlt, src: imageSrc)
+          else
+            img(
+              alt: placeholderAlt,
+              src: _placeholderImagePath,
+              attributes: {'aria-hidden': 'true'},
+            ),
+          if (hoverBackgroundSrc != null && hoverBackgroundSrc.isNotEmpty)
+            div(
+              classes: 'card-image-material-3-hover',
+              [
+                img(
+                  alt:
+                      'Decorated background for '
+                      'Material widget visualizations.',
+                  src: hoverBackgroundSrc,
+                  attributes: {'aria-hidden': 'true'},
+                ),
+              ],
+            ),
+        ] else ...[
+          // Standard catalog prefers vector, then image, then placeholder.
+          if (vector != null && vector.isNotEmpty)
+            raw(vector)
+          else if (imageSrc != null && imageSrc.isNotEmpty)
+            img(alt: imageAlt, src: imageSrc)
+          else
+            img(
+              alt: placeholderAlt,
+              src: _placeholderImagePath,
+              attributes: {'aria-hidden': 'true'},
+            ),
+        ],
+      ],
+    );
+  }
+}
+
+extension type _WidgetInfo(Map _data) {
+  String get name => _data['name'] as String;
+  String get link => _data['link'] as String;
+  String get description => _data['description'] as String? ?? '';
+  String? get vector => _data['vector'] as String?;
+  Map? get image => _data['image'] as Map?;
+  String? get imageSrc => image?['src'] as String?;
+  Map? get hoverBackground =>
+      _data['hoverBackground'] as Map?;
+  String? get hoverBackgroundSrc => hoverBackground?['src'] as String?;
+
+  List get categories {
+    final value = _data['categories'];
+    if (value is List) {
+      return value.cast();
+    }
+    return const [];
+  }
+
+  List get subcategories {
+    final value = _data['subcategories'];
+    if (value is List) {
+      return value.cast();
+    }
+    return const [];
+  }
+}
+
+extension type _CategoryInfo(Map _data) {
+  String get name => _data['name'] as String? ?? '';
+  String get description => _data['description'] as String? ?? '';
+  List<_SubcategoryInfo> get subcategories {
+    final value = _data['subcategories'] as List?;
+    if (value == null) return const [];
+    return value
+        .cast>()
+        .map(_SubcategoryInfo.new)
+        .toList(growable: false);
+  }
+}
+
+extension type _SubcategoryInfo(Map _data) {
+  String get name => _data['name'] as String? ?? '';
+  String? get color => _data['color'] as String?;
+}
diff --git a/site/lib/src/layouts/dash_layout.dart b/site/lib/src/layouts/dash_layout.dart
new file mode 100644
index 00000000000..2a5c322d8db
--- /dev/null
+++ b/site/lib/src/layouts/dash_layout.dart
@@ -0,0 +1,247 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert' show htmlEscape;
+
+import 'package:jaspr/jaspr.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../client/global_scripts.dart';
+import '../components/common/client/cookie_notice.dart';
+import '../components/layout/footer.dart';
+import '../components/layout/header.dart';
+import '../components/layout/sidenav.dart';
+import '../models/sidenav_model.dart';
+import '../style_hash.dart';
+import '../util.dart';
+
+/// The base Jaspr Content layout for wrapping site content.
+abstract class FlutterDocsLayout extends PageLayoutBase {
+  const FlutterDocsLayout();
+
+  @override
+  String get name;
+
+  @override
+  @mustCallSuper
+  Iterable buildHead(Page page) {
+    final pageData = page.data.page;
+    final siteData = page.data.site;
+    final pageTitle = (pageData['title'] ?? siteData['title']) as String;
+    final pageDescription = pageData['description'] as String? ?? '';
+
+    return [
+      ...super.buildHead(page),
+      if (pageData['noindex'] case final noIndex?
+          when noIndex == true || noIndex == 'true')
+        meta(name: 'robots', content: 'noindex'),
+      if (pageData['canonical'] case final String canonicalUrl
+          when canonicalUrl.isNotEmpty)
+        link(rel: 'canonical', href: canonicalUrl),
+      if (pageData['redirectTo'] case final String redirectTo
+          when redirectTo.isNotEmpty)
+        raw(''),
+      link(
+        rel: 'icon',
+        href: '/assets/images/branding/flutter/icon/64.png',
+        attributes: {'sizes': '64x64'},
+      ),
+      link(
+        rel: 'apple-touch-icon',
+        href: '/assets/images/branding/flutter/logo/flutter-logomark-320px.png',
+      ),
+      meta(name: 'twitter:card', content: 'summary'),
+      meta(name: 'twitter:site', content: '@flutterdev'),
+      meta(name: 'twitter:title', content: pageTitle),
+      meta(
+        name: 'twitter:description',
+        content: pageDescription,
+      ),
+
+      meta(attributes: {'property': 'og:title', 'content': pageTitle}),
+      meta(
+        attributes: {
+          'property': 'og:description',
+          'content': pageDescription,
+        },
+      ),
+      meta(attributes: {'property': 'og:url', 'content': page.path}),
+      meta(
+        attributes: {
+          'property': 'og:image',
+          'content': '/assets/images/flutter-logo-sharing.png',
+        },
+      ),
+
+      link(rel: 'preconnect', href: 'https://fonts.googleapis.com'),
+      link(
+        rel: 'preconnect',
+        href: 'https://fonts.gstatic.com',
+        attributes: {'crossorigin': ''},
+      ),
+      link(
+        rel: 'stylesheet',
+        href:
+            'https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap',
+      ),
+      link(
+        rel: 'stylesheet',
+        href:
+            'https://fonts.googleapis.com/css2?family=Google+Sans+Mono:wght@400;500;700&display=swap',
+      ),
+      link(
+        rel: 'stylesheet',
+        href:
+            'https://fonts.googleapis.com/css2?family=Google+Sans+Text:wght@400;500;700&display=swap',
+      ),
+      link(
+        rel: 'stylesheet',
+        href:
+            'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0..1,0',
+      ),
+      link(
+        rel: 'stylesheet',
+        href:
+            '/assets/css/main.css?'
+            'hash=${htmlEscape.convert(generatedStylesHash)}',
+      ),
+
+      if (pageData['js'] case final List jsList)
+        for (final js in jsList)
+          if (js case {'url': final String jsUrl, 'defer': final Object? defer})
+            script(
+              src: jsUrl,
+              attributes: {if (defer == 'true' || defer == true) 'defer': ''},
+            ),
+      script(
+        src:
+            'https://cdn.jsdelivr.net/npm/@justinribeiro/lite-youtube@1.8.2/lite-youtube.js',
+        attributes: {
+          'type': 'module',
+          'integrity': 'sha256-Jy0j0fUMJ2T3WxSEs2WjHLrS+3DlO7S9DItQtP55FII=',
+          'crossorigin': 'anonymous',
+          'referrerpolicy': 'no-referrer',
+        },
+      ),
+
+      // Set up tag manager and analytics.
+      if (productionBuild)
+        raw('''
+
+
+
+
+
+'''),
+    ];
+  }
+
+  @override
+  Component buildBody(Page page, Component child) {
+    final pageData = page.data.page;
+    final bodyClass = pageData['bodyClass'] as String?;
+    final pageUrl = page.url.startsWith('/') ? page.url : '/${page.url}';
+    final sideNavEntries = switch (page.data['sidenav']) {
+      final List sidenavData => navEntriesFromData(sidenavData),
+      _ => null,
+    };
+    final obsolete = pageData['obsolete'] == true;
+
+    return Component.fragment(
+      [
+        const Document.html(
+          attributes: {
+            'lang': 'en',
+            'dir': 'ltr',
+          },
+        ),
+        if (bodyClass != null) Document.body(attributes: {'class': bodyClass}),
+        if (productionBuild)
+          raw(
+            '',
+          ),
+        a(
+          id: 'skip-to-main',
+          classes: 'filled-button',
+          href: '#site-content-title',
+          [text('Skip to main content')],
+        ),
+        const CookieNotice(),
+        const DashHeader(),
+        div(id: 'site-below-header', [
+          div(id: 'site-main-row', [
+            if (sideNavEntries != null)
+              DashSideNav(
+                navEntries: sideNavEntries,
+                currentPageUrl: pageUrl,
+              ),
+            main_(
+              id: 'page-content',
+              classes: [
+                if (pageData['focusedLayout'] == true) 'focused',
+              ].toClasses,
+              [child],
+            ),
+            if (obsolete)
+              div(id: 'obsolete-banner', [
+                div(classes: 'text-center', [
+                  text('Some content on this page might be out of date.'),
+                ]),
+              ]),
+          ]),
+          const DashFooter(),
+        ]),
+        // The theme setting logic should remain before other scripts to
+        // avoid a flash of the initial theme on load.
+        raw('''
+
+      '''),
+        // Scroll the sidenav to the active item before other logic
+        // to avoid it jumping after page load.
+        raw('''
+
+      '''),
+        GlobalScripts(),
+      ],
+    );
+  }
+}
diff --git a/site/lib/src/layouts/doc_layout.dart b/site/lib/src/layouts/doc_layout.dart
new file mode 100644
index 00000000000..437c2d5d7e3
--- /dev/null
+++ b/site/lib/src/layouts/doc_layout.dart
@@ -0,0 +1,112 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../components/common/breadcrumbs.dart';
+import '../components/common/prev_next.dart';
+import '../components/layout/banner.dart';
+import '../components/layout/toc.dart';
+import '../components/layout/trailing_content.dart';
+import '../extensions/header_extractor.dart';
+import '../models/on_this_page_model.dart';
+import '../util.dart';
+import 'dash_layout.dart';
+
+/// The Jaspr Content layout to use for normal docs pages,
+/// adding elements such as breadcrumbs, TOC, and prev/next cards.
+class DocLayout extends FlutterDocsLayout {
+  const DocLayout();
+
+  @override
+  String get name => 'docs';
+
+  @override
+  Component buildBody(Page page, Component child) {
+    final pageData = page.data.page;
+    final siteData = page.data.site;
+
+    final pageTitle = pageData['title'] as String;
+    final showBanner =
+        (pageData['showBanner'] as bool?) ??
+        (siteData['showBanner'] as bool?) ??
+        false;
+    final tocData = _tocForPage(page);
+
+    return super.buildBody(
+      page,
+      Component.fragment(
+        [
+          if (tocData == null)
+            const Document.body(attributes: {'data-toc': 'false'})
+          else
+            NarrowTableOfContents(
+              tocData,
+              currentTitle: pageTitle,
+            ),
+          if (showBanner)
+            if (page.data['banner'] case final Map bannerData)
+              DashBanner(BannerContent.fromMap(bannerData)),
+          div(classes: 'after-leading-content', [
+            if (tocData != null)
+              aside(id: 'side-menu', [
+                WideTableOfContents(tocData),
+              ]),
+            article([
+              div(id: 'site-content-title', [
+                h1(id: 'document-title', [
+                  if (pageData['underscore_breaker_titles'] == true)
+                    ...splitByUnderscore(pageTitle)
+                  else
+                    text(pageTitle),
+                ]),
+                if (pageData['showBreadcrumbs'] != false)
+                  const PageBreadcrumbs(),
+              ]),
+
+              child,
+
+              PrevNext(
+                previousPage: _pageInfoFromObject(pageData['prev']),
+                nextPage: _pageInfoFromObject(pageData['next']),
+              ),
+              const TrailingContent(),
+            ]),
+          ]),
+        ],
+      ),
+    );
+  }
+
+  OnThisPageData? _tocForPage(Page page) {
+    final pageData = page.data.page;
+    final showToc = pageData['showToc'] as bool? ?? true;
+
+    // If 'showToc' was explicitly set to false, hide the toc.
+    if (!showToc) return null;
+
+    final onThisPageData = OnThisPageData.fromContentHeaders(
+      page.data['contentHeaders'] as List? ?? const [],
+      minLevel: pageData['minTocDepth'] as int? ?? 2,
+      maxLevel: pageData['maxTocDepth'] as int? ?? 3,
+    );
+
+    // If there are less than 2 top-level entries, hide the toc.
+    if (onThisPageData.topLevelEntries.length < 2) return null;
+
+    return onThisPageData;
+  }
+}
+
+({String url, String title})? _pageInfoFromObject(Object? data) {
+  if (data case {
+    'path': final String pageUrl,
+    'title': final String pageTitle,
+  }) {
+    return (url: pageUrl, title: pageTitle);
+  }
+
+  return null;
+}
diff --git a/site/lib/src/layouts/toc_layout.dart b/site/lib/src/layouts/toc_layout.dart
new file mode 100644
index 00000000000..9461f70a672
--- /dev/null
+++ b/site/lib/src/layouts/toc_layout.dart
@@ -0,0 +1,82 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../components/common/card.dart';
+import 'doc_layout.dart';
+
+class TocLayout extends DocLayout {
+  const TocLayout();
+
+  @override
+  String get name => 'toc';
+
+  @override
+  Component buildBody(Page page, Component child) {
+    return super.buildBody(
+      page,
+      Builder(
+        builder: (context) {
+          final normalizedCurrentUrl = _normalizeUrl(page.url);
+
+          // Find all direct child pages of the current page.
+          final childPages = [
+            for (final pageToCheck in context.pages)
+              if (_isDirectChild(normalizedCurrentUrl, pageToCheck.url))
+                pageToCheck,
+          ];
+
+          return Component.fragment([
+            if (childPages.isNotEmpty)
+              div(classes: 'card-grid very-wide', [
+                for (final childPage in childPages)
+                  Card(
+                    link: childPage.url,
+                    header: [
+                      span(classes: 'card-title', [
+                        text(childPage.data.page['title'] as String),
+                      ]),
+                    ],
+                    content: [
+                      if (childPage.data.page['description']
+                          case final String description)
+                        p([text(description)]),
+                    ],
+                    filled: true,
+                  ),
+              ]),
+            child,
+          ]);
+        },
+      ),
+    );
+  }
+
+  static String _normalizeUrl(String url) {
+    return url.endsWith('/') ? url : '$url/';
+  }
+
+  static bool _isDirectChild(String normalizedCurrentUrl, String otherUrl) {
+    final normalizedOtherUrl = _normalizeUrl(otherUrl);
+
+    // Skip if the page URL doesn't start with the current URL.
+    if (!normalizedOtherUrl.startsWith(normalizedCurrentUrl)) return false;
+
+    // Skip if it's the current page itself.
+    if (normalizedOtherUrl == normalizedCurrentUrl) return false;
+
+    // Extract the remaining path after the current URL.
+    final remainingPath = normalizedOtherUrl.substring(
+      normalizedCurrentUrl.length,
+    );
+
+    // Check if this is a direct child by ensuring there's only one
+    // path segment (no additional slashes beyond a possible trailing slash).
+    final segments = remainingPath.split('/').where((s) => s.isNotEmpty);
+
+    return segments.length == 1;
+  }
+}
diff --git a/site/lib/src/loaders/data_processor.dart b/site/lib/src/loaders/data_processor.dart
new file mode 100644
index 00000000000..adef894405c
--- /dev/null
+++ b/site/lib/src/loaders/data_processor.dart
@@ -0,0 +1,94 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io' show FileSystemException, Process;
+
+import 'package:jaspr_content/jaspr_content.dart';
+import 'package:path/path.dart' as path;
+
+/// A shared data loader to add data to each loaded page.
+final class DataProcessor implements DataLoader {
+  @override
+  Future loadData(Page page) async {
+    _loadLastModified(page);
+  }
+
+  /// Adds data about the last modified date of the page.
+  static void _loadLastModified(Page page) {
+    final pageLoader = page.loader;
+    if (pageLoader is! FilesystemLoader) return;
+
+    final sourcePath = path.canonicalize(
+      path.join(pageLoader.directory, page.path),
+    );
+
+    final inputPath = path.relative(sourcePath, from: '..');
+    page.apply(
+      data: {
+        'page': {
+          'date': ?_lastModifiedDateForPath(inputPath),
+          'inputPath': inputPath,
+          if (page.data.page['sitemap'] == null)
+            'sitemap': {
+              'lastmod': _lastModifiedDateForPath(inputPath),
+            },
+        },
+      },
+    );
+  }
+}
+
+/// Determines the last modified date for a given path
+/// in the form `yyyy-mm-dd`.
+///
+/// Uses `git log` to get the last modified date from the git history.
+/// Returns `null` if no date can be determined.
+String? _lastModifiedDateForPath(String inputPath) =>
+    _lastModifiedPerPath[inputPath]?.formatted;
+
+final Map _lastModifiedPerPath = () {
+  final fileLastModified = {};
+
+  try {
+    final output =
+        Process.runSync('git', [
+              'log',
+              '--name-only',
+              '--format=commit-date:%cI',
+              '--',
+              '../src/content',
+            ]).stdout
+            as String;
+
+    final lines = const LineSplitter().convert(output);
+    DateTime? currentCommitDate;
+    for (final line in lines) {
+      // Check if the line is a commit date line.
+      if (line.split('commit-date:') case [_, final dateString]) {
+        // Extract the date string and try to parse it.
+        currentCommitDate = DateTime.tryParse(dateString);
+      } else if (line.isNotEmpty) {
+        // If it's a non-empty line and a date is set, it's a file path.
+        if (currentCommitDate case final lastModifiedTime?) {
+          // Only set the last modified time for this path
+          // if we haven't already stored a later modified time.
+          fileLastModified.putIfAbsent(
+            line,
+            () => lastModifiedTime,
+          );
+        }
+      }
+    }
+  } on FileSystemException catch (_) {
+    // Ignore and fall through to return an empty list.
+    // We just won't render the last updated time.
+  }
+
+  return fileLastModified;
+}();
+
+extension on DateTime {
+  String get formatted => '$year-$month-$day';
+}
diff --git a/site/lib/src/markdown/alert_syntax.dart b/site/lib/src/markdown/alert_syntax.dart
new file mode 100644
index 00000000000..5c1473209cb
--- /dev/null
+++ b/site/lib/src/markdown/alert_syntax.dart
@@ -0,0 +1,199 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:markdown/markdown.dart' as md;
+
+/// A custom Markdown block syntax for alerts that are
+/// opened and closed with `:::`.
+///
+/// Example:
+///
+/// ```md
+/// :::important The title of my alert
+/// The content of my alert.
+/// :::
+/// ```
+///
+/// This renders as HTML similar to:
+/// ```html
+/// 
+/// ```
+final class AlertBlockSyntax extends md.BlockSyntax {
+  @override
+  RegExp get pattern => RegExp(r'^:::([a-zA-Z-]+)(?:\s+(.*))?$');
+
+  const AlertBlockSyntax();
+
+  @override
+  bool canParse(md.BlockParser parser) {
+    return pattern.hasMatch(parser.current.content);
+  }
+
+  @override
+  md.Node? parse(md.BlockParser parser) {
+    final match = pattern.firstMatch(parser.current.content);
+    if (match == null) return null;
+
+    final alertType = _AlertType.fromTypeId(match.group(1)!.toLowerCase());
+    var title = match.group(2)?.trim();
+
+    if (title == null || title.isEmpty) {
+      title = alertType.defaultTitle;
+    }
+
+    // Advance past the opening line.
+    parser.advance();
+
+    // Collect content lines until we find the closing :::.
+    final contentLines = [];
+    while (!parser.isDone) {
+      final line = parser.current.content;
+      if (line.trim() == ':::') {
+        // Consume the closing line.
+        parser.advance();
+        break;
+      }
+      contentLines.add(line);
+      parser.advance();
+    }
+
+    // Create a new BlockParser with the same document context.
+    // This preserves link references and other document-level state.
+    final contentNodes = md.BlockParser(
+      contentLines.map(md.Line.new).toList(growable: false),
+      parser.document,
+    ).parseLines(parentSyntax: this);
+
+    final alertChildren = [];
+
+    // If title is provided, create and add a header.
+    if (title != null && title.isNotEmpty) {
+      final headerChildren = [];
+
+      // If the type has a corresponding icon, add it to the header.
+      if (alertType.iconId case final iconId?) {
+        final iconElement = md.Element('span', [md.Text(iconId)])
+          ..attributes['class'] = 'material-symbols'
+          ..attributes['translate'] = 'no'
+          ..attributes['aria-hidden'] = 'true';
+        headerChildren.add(iconElement);
+      }
+
+      // Parse the title as inline Markdown to support links, emphasis, etc.
+      final titleNodes = parser.document.parseInline(title);
+      headerChildren.add(md.Element('span', titleNodes));
+
+      alertChildren.add(
+        md.Element('div', headerChildren)..attributes['class'] = 'alert-header',
+      );
+    }
+
+    final contentElement = md.Element('div', contentNodes)
+      ..attributes['class'] = 'alert-content';
+    alertChildren.add(contentElement);
+
+    final alertElement = md.Element('aside', alertChildren)
+      ..attributes['class'] = 'alert ${alertType.cssClass}';
+
+    return alertElement;
+  }
+}
+
+/// The supported types of alerts, otherwise known as asides or callouts.
+enum _AlertType {
+  experimental(
+    cssClass: 'alert-warning',
+    iconId: 'construction',
+    defaultTitle: 'Experimental',
+  ),
+  note(
+    cssClass: 'alert-info',
+    iconId: 'info',
+    defaultTitle: 'Note',
+  ),
+  flutterNote(
+    cssClass: 'alert-info',
+    iconId: 'flutter',
+    defaultTitle: 'Flutter note',
+  ),
+  versionNote(
+    cssClass: 'alert-info',
+    iconId: 'merge_type',
+    defaultTitle: 'Version note',
+  ),
+  tip(
+    cssClass: 'alert-success',
+    iconId: 'lightbulb',
+    defaultTitle: 'Tip',
+  ),
+  recommend(
+    cssClass: 'alert-success',
+    iconId: 'bolt',
+    defaultTitle: 'Recommended',
+  ),
+  important(
+    cssClass: 'alert-important',
+    iconId: 'feedback',
+    defaultTitle: 'Important',
+  ),
+  warning(
+    cssClass: 'alert-warning',
+    iconId: 'warning',
+    defaultTitle: 'Warning',
+  ),
+  caution(
+    cssClass: 'alert-error',
+    iconId: 'error',
+    defaultTitle: 'Caution',
+  ),
+  secondary(
+    cssClass: 'alert-secondary',
+  );
+
+  /// The CSS class to add to `aside` element
+  final String cssClass;
+
+  /// The Material Symbols icon ID to display in the alert header.
+  ///
+  /// If `null`, no icon is displayed.
+  final String? iconId;
+
+  /// The default title to display in the alert header if
+  /// no title is explicitly provided in the Markdown.
+  ///
+  /// If `null`, no title will be displayed if one wasn't explicitly provided.
+  final String? defaultTitle;
+
+  const _AlertType({
+    required this.cssClass,
+    this.iconId,
+    this.defaultTitle,
+  });
+
+  /// Returns the [_AlertType] corresponding to the given [typeId].
+  ///
+  /// If the [typeId] does not match any known type,
+  /// an [ArgumentError] is thrown.
+  static _AlertType fromTypeId(String typeId) => switch (typeId) {
+    'experimental' => _AlertType.experimental,
+    'note' => _AlertType.note,
+    'flutter-note' => _AlertType.flutterNote,
+    'version-note' => _AlertType.versionNote,
+    'tip' => _AlertType.tip,
+    'recommend' => _AlertType.recommend,
+    'important' => _AlertType.important,
+    'warning' => _AlertType.warning,
+    'caution' => _AlertType.caution,
+    'secondary' => _AlertType.secondary,
+    _ => throw ArgumentError('Unknown alert type: $typeId'),
+  };
+}
diff --git a/site/lib/src/markdown/attribute_syntax.dart b/site/lib/src/markdown/attribute_syntax.dart
new file mode 100644
index 00000000000..9a213317fac
--- /dev/null
+++ b/site/lib/src/markdown/attribute_syntax.dart
@@ -0,0 +1,68 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:markdown/markdown.dart' as md;
+
+import '../util.dart';
+
+/// A `package:markdown` extension that adds support for
+/// attribute syntax as a standalone block.
+///
+/// Supports syntax like:
+///
+/// - `{: #new-id}` - Sets the element's HTML ID.
+/// - `{: .custom-class}` - Adds a class to the element.
+/// - `{: #custom-id .custom-class}` - Set the element's ID and adds a class.
+/// - `{: .class1 .class2}` - Add multiple classes.
+///
+/// This works by detecting attribute blocks and
+/// applying them to the preceding block element.
+final class AttributeBlockSyntax extends md.BlockSyntax {
+  const AttributeBlockSyntax();
+
+  static final RegExp _pattern = RegExp(r'^\{:\s*([^}]+)\}\s*$');
+
+  @override
+  RegExp get pattern => _pattern;
+
+  @override
+  md.Node? parse(md.BlockParser parser) {
+    final currentLine = parser.current;
+    final match = pattern.firstMatch(currentLine.content);
+    if (match == null) return null;
+
+    final attributeString = match[1]!.trim();
+    parser.advance();
+
+    // Create a special marker element that will be processed later.
+    // This allows us to apply attributes during post-processing in
+    // the `extensions/attribute_processor.dart` extension.
+    final attributes = parseAttributes(attributeString);
+    return md.Element.empty('attribute-marker')..attributes.addAll(attributes);
+  }
+}
+
+/// An inline syntax for parsing attributes in the form `{: #id .class}`.
+///
+/// This allows attributes to be added inline, such as:
+///
+/// - After links: `[text](url){: .external}`
+/// - At the end of paragraphs: `Some text{: .highlight}`
+/// - After other inline elements: `**bold**{: .important}`
+final class AttributeInlineSyntax extends md.InlineSyntax {
+  AttributeInlineSyntax() : super(r'\{:\s*([^}]+)\}');
+
+  @override
+  bool onMatch(md.InlineParser parser, Match match) {
+    final attributeString = match[1]!.trim();
+    final attributes = parseAttributes(attributeString);
+
+    // Create an inline attribute marker that can be processed later.
+    final marker = md.Element.empty('attribute-marker');
+    marker.attributes.addAll(attributes);
+
+    parser.addNode(marker);
+    return true;
+  }
+}
diff --git a/site/lib/src/markdown/fenced_code_block_syntax.dart b/site/lib/src/markdown/fenced_code_block_syntax.dart
new file mode 100644
index 00000000000..a1be4917c35
--- /dev/null
+++ b/site/lib/src/markdown/fenced_code_block_syntax.dart
@@ -0,0 +1,143 @@
+// Copied from https://github.com/dart-lang/tools/blob/main/pkgs/markdown/lib/src/block_syntaxes/fenced_code_block_syntax.dart
+//
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:markdown/markdown.dart';
+// Used as this is file is copied from the Markdown package and updated.
+// ignore: implementation_imports
+import 'package:markdown/src/util.dart' as unsafe_md_util;
+
+/// Parses preformatted code blocks between two ``` sequences.
+class CustomFencedCodeBlockSyntax extends BlockSyntax {
+  const CustomFencedCodeBlockSyntax();
+
+  @override
+  RegExp get pattern => _codeFencePattern;
+
+  @override
+  Node parse(BlockParser parser) {
+    final openingFence = _FenceMatch.fromMatch(
+      pattern.firstMatch(
+        unsafe_md_util.escapePunctuation(parser.current.content),
+      )!,
+    );
+
+    var text = parseChildLines(
+      parser,
+      openingFence.marker,
+      openingFence.indent,
+    ).map((e) => e.content).join('\n');
+
+    if (parser.document.encodeHtml) {
+      text = unsafe_md_util.escapeHtml(text, escapeApos: false);
+    }
+    if (text.isNotEmpty) {
+      text = '$text\n';
+    }
+
+    final code = Element.text('code', text);
+    if (openingFence.hasLanguage) {
+      var language = unsafe_md_util.decodeHtmlCharacters(openingFence.language);
+      if (parser.document.encodeHtml) {
+        language = unsafe_md_util.escapeHtmlAttribute(language);
+      }
+      code.attributes['class'] = 'language-$language';
+    }
+    if (openingFence.hasMetadata) {
+      final metadata = unsafe_md_util.decodeHtmlCharacters(
+        openingFence.metadata.join(' '),
+      );
+      code.attributes['data-meta'] = metadata;
+    }
+
+    return Element('pre', [code]);
+  }
+
+  String _removeIndentation(String content, int length) {
+    final text = content.replaceFirst(RegExp('^\\s{0,$length}'), '');
+    return content.substring(content.length - text.length);
+  }
+
+  @override
+  List parseChildLines(
+    BlockParser parser, [
+    String openingMarker = '',
+    int indent = 0,
+  ]) {
+    final childLines = [];
+
+    parser.advance();
+
+    _FenceMatch? closingFence;
+    while (!parser.isDone) {
+      final match = pattern.firstMatch(parser.current.content);
+      closingFence = match == null ? null : _FenceMatch.fromMatch(match);
+
+      // Closing code fences can't have info strings:
+      // https://spec.commonmark.org/0.30/#example-147
+      if (closingFence == null ||
+          !closingFence.marker.startsWith(openingMarker) ||
+          closingFence.hasInfo) {
+        childLines.add(
+          Line(_removeIndentation(parser.current.content, indent)),
+        );
+        parser.advance();
+      } else {
+        parser.advance();
+        break;
+      }
+    }
+
+    // https://spec.commonmark.org/0.30/#example-127
+    // https://spec.commonmark.org/0.30/#example-128
+    if (closingFence == null &&
+        childLines.isNotEmpty &&
+        childLines.last.isBlankLine) {
+      childLines.removeLast();
+    }
+
+    return childLines;
+  }
+}
+
+class _FenceMatch {
+  _FenceMatch._({
+    required this.indent,
+    required this.marker,
+    required this.info,
+  });
+
+  factory _FenceMatch.fromMatch(RegExpMatch match) {
+    final marker = match.namedGroup('backtick')!;
+    final info = match.namedGroup('backtickInfo')!;
+
+    return _FenceMatch._(
+      indent: match[1]!.length,
+      marker: marker,
+      info: info.trim(),
+    );
+  }
+
+  final int indent;
+  final String marker;
+
+  final String info;
+
+  late final List _splitInfo = info.split(' ');
+
+  String get language => _splitInfo.first;
+
+  bool get hasMetadata => _splitInfo.length > 1;
+
+  List get metadata => hasMetadata ? _splitInfo.sublist(1) : [];
+
+  bool get hasInfo => info.isNotEmpty;
+
+  bool get hasLanguage => language.isNotEmpty;
+}
+
+final _codeFencePattern = RegExp(
+  r'^(\s{0,3})(?`{3,})(?[^`]*)$',
+);
diff --git a/site/lib/src/markdown/header_syntax.dart b/site/lib/src/markdown/header_syntax.dart
new file mode 100644
index 00000000000..e4be28e7e11
--- /dev/null
+++ b/site/lib/src/markdown/header_syntax.dart
@@ -0,0 +1,54 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:markdown/markdown.dart' as md;
+
+import '../util.dart';
+
+/// A custom header syntax that extends the default header syntax to support:
+///
+/// 1. Inline attribute syntax at the end of headers,
+///    such as `# Title {: #custom-id .class}`)`.
+/// 2. Auto-generated IDs using slugify when no ID is provided.
+final class HeaderWithAttributesSyntax extends md.HeaderSyntax {
+  const HeaderWithAttributesSyntax();
+
+  static final RegExp _attributeEndPattern = RegExp(r'\s*\{:\s*([^}]+)\}\s*$');
+
+  @override
+  md.Node parse(md.BlockParser parser) {
+    final element = super.parse(parser) as md.Element;
+
+    // Check if the header text ends with attribute syntax.
+    final children = element.children;
+    if (children != null && children.isNotEmpty) {
+      final lastChild = children.last;
+      var childText = lastChild.textContent;
+      final match = _attributeEndPattern.firstMatch(childText);
+
+      if (match != null) {
+        // Extract and parse the attributes.
+        final attributeString = match.group(1)!.trim();
+        final attributes = parseAttributes(attributeString);
+
+        // Remove the attribute syntax from the text.
+        final cleanText = childText.substring(0, match.start).trim();
+        childText = cleanText;
+        children[children.length - 1] = md.UnparsedContent(cleanText);
+
+        // Apply the parsed attributes to the header element.
+        element.attributes.addAll(attributes);
+      }
+
+      // If no ID was specified otherwise, generate an ID from the content.
+      if (!element.attributes.containsKey('id')) {
+        if (childText.isNotEmpty) {
+          element.attributes['id'] = slugify(childText);
+        }
+      }
+    }
+
+    return element;
+  }
+}
diff --git a/site/lib/src/markdown/markdown_parser.dart b/site/lib/src/markdown/markdown_parser.dart
new file mode 100644
index 00000000000..430c2eeba31
--- /dev/null
+++ b/site/lib/src/markdown/markdown_parser.dart
@@ -0,0 +1,204 @@
+import 'dart:collection';
+
+import 'package:html/parser.dart' as html;
+// ignore: implementation_imports
+import 'package:html/src/token.dart' as html;
+// ignore: implementation_imports
+import 'package:html/src/tokenizer.dart' as html;
+import 'package:jaspr/server.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+import 'package:markdown/markdown.dart' as md;
+import 'package:markdown_description_list/markdown_description_list.dart';
+
+import '../extensions/registry.dart';
+import 'alert_syntax.dart';
+import 'attribute_syntax.dart';
+import 'fenced_code_block_syntax.dart';
+import 'header_syntax.dart';
+
+/// The `package:markdown` block syntaxes to apply when parsing Markdown.
+const List _blockSyntaxes = [
+  JasprHtmlBlockSyntax(),
+  CustomFencedCodeBlockSyntax(),
+  HeaderWithAttributesSyntax(),
+  AttributeBlockSyntax(),
+  AlertBlockSyntax(),
+  DescriptionListSyntax(),
+  md.TableSyntax(),
+  md.FootnoteDefSyntax(),
+  md.EmptyBlockSyntax(),
+  md.BlockquoteSyntax(),
+  md.HorizontalRuleSyntax(),
+  md.UnorderedListSyntax(),
+  md.OrderedListSyntax(),
+  md.LinkReferenceDefinitionSyntax(),
+  md.ParagraphSyntax(),
+];
+
+/// The `package:markdown` inline syntaxes to apply when parsing Markdown.
+final List _inlineSyntaxes = [
+  md.InlineHtmlSyntax(),
+  AttributeInlineSyntax(),
+];
+
+/// A component to use when needing to dynamically parse Markdown content and
+/// render it within a different Jaspr component.
+class DashMarkdown extends AsyncStatelessComponent {
+  static const NodesBuilder _nodeBuilder = NodesBuilder([]);
+
+  const DashMarkdown({
+    required this.content,
+    this.inline = false,
+  });
+
+  final String content;
+  final bool inline;
+
+  @override
+  Future build(BuildContext context) async {
+    final currentPage = context.page;
+    final markdownNodes = _defaultMarkdownDocument.parse(content);
+    var nodes = DashMarkdownParser.buildNodes(markdownNodes);
+    for (final extension in allNodeProcessingExtensions) {
+      nodes = await extension.apply(currentPage, nodes);
+    }
+
+    return _nodeBuilder.build(nodes);
+  }
+}
+
+/// Creates a `package:markdown` document with our custom syntaxes configured.
+md.Document get _defaultMarkdownDocument => md.Document(
+  blockSyntaxes: _blockSyntaxes,
+  inlineSyntaxes: _inlineSyntaxes,
+  withDefaultBlockSyntaxes: false,
+);
+
+/// Uses our custom Markdown configuration and syntaxes to
+/// parse the specified [markdownString] into HTML.
+///
+/// Assumes it's parsing at the block-level if [inline] isn't set to `true`.
+String parseMarkdownToHtml(String markdownString, {bool inline = false}) {
+  final nodes = inline
+      ? _defaultMarkdownDocument.parseInline(markdownString)
+      : _defaultMarkdownDocument.parse(markdownString);
+  final renderer = md.HtmlRenderer();
+  return renderer.render(nodes);
+}
+
+final RegExp _markdownFilePattern = RegExp(r'.*\.md$');
+
+class DashMarkdownParser implements PageParser {
+  const DashMarkdownParser();
+
+  @override
+  Pattern get pattern => _markdownFilePattern;
+
+  @override
+  List parsePage(Page page) {
+    final markdownNodes = _defaultMarkdownDocument.parse(page.content);
+
+    return buildNodes(markdownNodes);
+  }
+
+  static List buildNodes(Iterable markdownNodes) {
+    final rootChildren = [];
+    final root = ElementNode('_', {}, rootChildren);
+    final stack = Queue();
+    stack.add(root);
+    var currentNodes = rootChildren;
+
+    for (final node in markdownNodes) {
+      if (node is HtmlText) {
+        final tokenizer = html.HtmlTokenizer(
+          node.text,
+          lowercaseElementName: false,
+        );
+
+        while (tokenizer.moveNext()) {
+          final token = tokenizer.current;
+
+          if (token.kind == html.TokenKind.parseError) {
+            final error = (token as html.ParseErrorToken).data;
+            if (error == 'expected-tag-name-but-got-question-mark') {
+              // Ignore opening of processing instructions.
+              continue;
+            } else {
+              throw AssertionError('Unexpected parse error: ${token.data}');
+            }
+          }
+
+          if (token.kind == html.TokenKind.startTag) {
+            final tag = (token as html.StartTagToken).name ?? '';
+            final element = ElementNode(tag, {
+              for (final MapEntry(:key, :value) in token.data.entries)
+                key.toString(): value,
+            }, []);
+            currentNodes.add(element);
+            final selfClosing = token.selfClosing || _isVoidElement(tag);
+            if (!selfClosing) {
+              stack.add(element);
+              currentNodes = element.children!;
+            }
+          } else if (token.kind == html.TokenKind.endTag) {
+            if (stack.last.tag != (token as html.EndTagToken).name) {
+              // If the end tag does not match the last opened tag, ignore it.
+              continue;
+            }
+            stack.removeLast();
+            currentNodes = stack.last.children!;
+          } else if (token.kind == html.TokenKind.characters ||
+              token.kind == html.TokenKind.spaceCharacters) {
+            currentNodes.add(TextNode((token as html.StringToken).data));
+          } else if (token.kind == html.TokenKind.comment) {
+            var data = (token as html.CommentToken).data;
+            if (data.startsWith('?') && data.endsWith('?')) {
+              data = data.substring(1, data.length - 1);
+            }
+            currentNodes.add(TextNode('', raw: true));
+          } else if (token.kind == html.TokenKind.doctype) {
+            // Ignore doctype tokens.
+            continue;
+          }
+        }
+      } else if (node is md.Text) {
+        currentNodes.addAll(
+          HtmlParser.buildNodes(html.parseFragment(node.text).nodes),
+        );
+      } else if (node is md.Element) {
+        final nodeChildren = node.children;
+        currentNodes.add(
+          ElementNode(
+            node.tag,
+            {
+              'id': ?node.generatedId,
+              ...node.attributes,
+            },
+            nodeChildren != null ? buildNodes(nodeChildren) : null,
+          ),
+        );
+      }
+    }
+
+    return rootChildren;
+  }
+}
+
+/// Returns whether the specified HTML [tag] corresponds to a void HTML element,
+/// meaning it can't have any child nodes.
+bool _isVoidElement(String tag) => const {
+  'area',
+  'base',
+  'br',
+  'col',
+  'embed',
+  'hr',
+  'img',
+  'input',
+  'link',
+  'meta',
+  'param',
+  'source',
+  'track',
+  'wbr',
+}.contains(tag.toLowerCase());
diff --git a/site/lib/src/models/flutter_release_model.dart b/site/lib/src/models/flutter_release_model.dart
new file mode 100644
index 00000000000..1065cab5260
--- /dev/null
+++ b/site/lib/src/models/flutter_release_model.dart
@@ -0,0 +1,82 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+import 'package:universal_web/js_interop.dart';
+
+/// Represents a Flutter release loaded from the Flutter releases endpoint.
+class FlutterRelease {
+  FlutterRelease({
+    required this.url,
+    required this.version,
+    required this.channel,
+    required this.dartSdkVersion,
+    required this.architecture,
+    required this.hash,
+    required this.releaseDate,
+  });
+
+  factory FlutterRelease.fromJson(Map json, String baseUrl) {
+    return FlutterRelease(
+      url: '$baseUrl/${json['archive'] as String}',
+      version: json['version'] as String,
+      channel: json['channel'] as String,
+      dartSdkVersion:
+          (json['dart_sdk_version'] as String?)?.split(' ')[0] ?? '-',
+      architecture: (json['dart_sdk_arch'] as String?) ?? 'x64',
+      hash: (json['hash'] as String).substring(0, 7),
+      releaseDate: Date(Date.parse(json['release_date'] as String)),
+    );
+  }
+
+  final String url;
+  final String version;
+  final String channel;
+  final String dartSdkVersion;
+  final String architecture;
+  final String hash;
+  final Date releaseDate;
+
+  static const baseReleasesUrl =
+      'https://storage.googleapis.com/flutter_infra_release/releases/';
+
+  static final Map>>
+  _flutterReleasesFutures = {};
+
+  /// Fetches Flutter release JSON for the given OS and caches the result.
+  static Future> fetchFlutterReleases(String os) {
+    return _flutterReleasesFutures[os] ??= http
+        .get(Uri.parse('${baseReleasesUrl}releases_$os.json'))
+        .then((response) {
+          if (response.statusCode == 200) {
+            final releases = jsonDecode(response.body) as Map;
+            final baseUrl = releases['base_url'] as String;
+            final releasesList = releases['releases'] as List;
+            return releasesList.map((release) {
+              return FlutterRelease.fromJson(
+                release as Map,
+                baseUrl,
+              );
+            }).toList();
+          } else {
+            throw Exception('Failed to load Flutter releases');
+          }
+        });
+  }
+}
+
+/// The JavaScript Date object.
+///
+/// Used for formatting dates on the client side, as a
+/// lightweight alternative to depending on the 'intl' package.
+extension type Date._(JSObject date) implements JSObject {
+  external Date(int date);
+
+  external static int parse(String dateString);
+
+  external String toLocaleDateString();
+  external int valueOf();
+}
diff --git a/site/lib/src/models/learning_resource_model.dart b/site/lib/src/models/learning_resource_model.dart
new file mode 100644
index 00000000000..12e0224df13
--- /dev/null
+++ b/site/lib/src/models/learning_resource_model.dart
@@ -0,0 +1,108 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:universal_web/web.dart' as web;
+
+final class LearningResource {
+  LearningResource({
+    required this.name,
+    required this.description,
+    required this.type,
+    required this.tags,
+    this.link,
+    this.imageUrl,
+  });
+
+  /// Creates a [LearningResource] from a Map, used on the server
+  /// when parsing the yaml data files.
+  factory LearningResource.fromMap(Map map) {
+    return LearningResource(
+      name: map['name'] as String,
+      description: map['description'] as String,
+      type: map['type'] as String,
+      tags: (map['tags'] as List?)?.cast() ?? [],
+      link: (
+        label: (map['link'] as Map)['label'] as String,
+        url: (map['link'] as Map)['url'] as String,
+      ),
+      imageUrl: map['imageUrl'] as String?,
+    );
+  }
+
+  /// Creates a [LearningResource] from a DOM Element, used on the client
+  /// for recreating and filtering existing resources.
+  factory LearningResource.fromElement(web.Element element) {
+    final dataType = element.getAttribute('data-type') ?? '';
+    final dataTags = element.getAttribute('data-tags') ?? '';
+    final dataDescription = element.getAttribute('data-description') ?? '';
+
+    return LearningResource(
+      name: element.id,
+      type: dataType,
+      tags: dataTags.split(',').map((t) => t.trim().toLowerCase()).toList(),
+      description: dataDescription,
+    );
+  }
+
+  final String name;
+  final String description;
+  final String type;
+  final List tags;
+  final ({String url, String label})? link;
+  final String? imageUrl;
+}
+
+enum LearningResourceType {
+  tutorial('Tutorial', ['codelab', 'tutorial']),
+  sampleCode('Sample code', ['quickstart', 'demo', 'sample', 'sample code']),
+  workshop('Workshop', ['workshop', 'video']),
+  recipe('Recipe', ['recipe', 'how to', 'cookbook']);
+
+  const LearningResourceType(this.label, this.tags);
+
+  final String label;
+  final List tags;
+}
+
+enum LearningResourceTag {
+  ai('AI', ['ai', 'gemini', 'llm']),
+  animation('Animation', ['animations', 'animate', 'animation']),
+  architecture('Architecture', [
+    'state-management',
+    'architecture',
+    'provider',
+    'bloc',
+    'stream',
+  ]),
+  cupertino('Cupertino', ['cupertino', 'ios', 'macos']),
+  design('Design', ['design', 'widgets']),
+  desktop('Desktop', ['windows', 'macos', 'linux']),
+  firebase('Firebase', ['firebase', 'firestore', 'cloud']),
+  goodForBeginners('Good for beginners', ['beginner', 'beginners']),
+  googleApis('Google APIs', ['google', 'gemini', 'maps', 'firebase', 'cloud']),
+  ios('iOS', ['cupertino', 'ios']),
+  layout('Layout', ['layout', 'lists', 'scrolling', 'widgets']),
+  material('Material', ['material', 'android']),
+  routingAndNavigation('Routing and navigation', [
+    'routing',
+    'route',
+    'navigation',
+    'navigator',
+  ]),
+  stateManagement('State management', [
+    'state-management',
+    'architecture',
+    'provider',
+    'bloc',
+    'stream',
+  ]),
+  testing('Testing', ['testing', 'tests', 'test', 'perf', 'performance']),
+  web('Web', ['web', 'wasm']),
+  widgets('Widgets', ['widgets', 'layout']);
+
+  const LearningResourceTag(this.label, this.tags);
+
+  final String label;
+  final List tags;
+}
diff --git a/site/lib/src/models/on_this_page_model.dart b/site/lib/src/models/on_this_page_model.dart
new file mode 100644
index 00000000000..2efd3eb7a4c
--- /dev/null
+++ b/site/lib/src/models/on_this_page_model.dart
@@ -0,0 +1,75 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import '../extensions/header_extractor.dart';
+
+class OnThisPageData {
+  final List topLevelEntries;
+
+  OnThisPageData(this.topLevelEntries);
+
+  factory OnThisPageData.fromContentHeaders(
+    List headers, {
+    required int minLevel,
+    required int maxLevel,
+  }) {
+    final rootEntries = [];
+    final levelMap = {};
+
+    for (final header in headers) {
+      // Clear entries at this level and below
+      // so that they aren't tracked any more.
+      for (
+        var removeLevel = header.level;
+        removeLevel <= maxLevel;
+        removeLevel += 1
+      ) {
+        levelMap.remove(removeLevel);
+      }
+
+      final id = header.attributes['id'];
+      final classes = header.attributes['class']?.split(' ') ?? [];
+
+      // Check if header should be skipped.
+      if (id == null ||
+          classes.contains('no_toc') ||
+          header.level < minLevel ||
+          header.level > maxLevel) {
+        continue;
+      }
+
+      final entry = OnThisPageEntry(
+        id: id,
+        text: header.text,
+        children: [],
+      );
+
+      // Check if this is a root level entry.
+      if (header.level == minLevel) {
+        rootEntries.add(entry);
+        levelMap[header.level] = entry;
+      } else {
+        // Look for parent at exactly one level above.
+        if (levelMap[header.level - 1] case final parent?) {
+          parent.children.add(entry);
+          levelMap[header.level] = entry;
+        }
+      }
+    }
+
+    return OnThisPageData(rootEntries);
+  }
+}
+
+final class OnThisPageEntry {
+  final String id;
+  final String text;
+  final List children;
+
+  const OnThisPageEntry({
+    required this.id,
+    required this.text,
+    this.children = const [],
+  });
+}
diff --git a/site/lib/src/models/sidenav_model.dart b/site/lib/src/models/sidenav_model.dart
new file mode 100644
index 00000000000..c0e21162ad5
--- /dev/null
+++ b/site/lib/src/models/sidenav_model.dart
@@ -0,0 +1,106 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// Builds a navigation structure for the site sidenav from
+/// a loaded YAML or JSON structure.
+///
+/// Expects data in the format used by `src/_data/sidenav.yml`.
+List navEntriesFromData(List data) => [
+  for (final item in data)
+    switch (item) {
+      'divider' => const NavEntry.divider(),
+      Map() => NavEntry._fromMap(item),
+      _ => throw ArgumentError('Invalid nav entry format: $item'),
+    },
+];
+
+/// An individual entry in the sidenav.
+sealed class NavEntry {
+  const NavEntry();
+
+  const factory NavEntry.header(String title) = NavHeader;
+  const factory NavEntry.divider() = NavDivider;
+  const factory NavEntry.link(String title, String permalink) = NavLink;
+  const factory NavEntry.section(
+    String title,
+    List children, {
+    String? permalink,
+    bool expanded,
+    bool hiddenChildren,
+  }) = NavSection;
+
+  factory NavEntry._fromMap(Map item) {
+    // Check for special entries that indicate a different entry type.
+    if (item.containsKey('header')) {
+      return NavEntry.header(item['header'] as String);
+    }
+
+    final title = item['title'] as String?;
+    if (title == null) {
+      throw ArgumentError(
+        'Non-divider and non-header nav entries must '
+        "have a 'title' specified.",
+      );
+    }
+
+    final childrenData = item['children'] as List?;
+
+    if (childrenData != null) {
+      // If specified, build children recursively.
+      final children = navEntriesFromData(childrenData);
+      if (children.isNotEmpty) {
+        final permalink = item['permalink'] as String?;
+        final expanded = item['expanded'] as bool? ?? false;
+        final hiddenChildren = item['hiddenChildren'] as bool? ?? false;
+        return NavEntry.section(
+          title,
+          children,
+          permalink: permalink,
+          expanded: expanded,
+          hiddenChildren: hiddenChildren,
+        );
+      }
+    } else {
+      final permalink = item['permalink'] as String?;
+      if (permalink != null) {
+        return NavEntry.link(title, permalink);
+      }
+    }
+
+    throw ArgumentError('Invalid nav entry format: $item');
+  }
+}
+
+final class NavHeader extends NavEntry {
+  final String title;
+
+  const NavHeader(this.title);
+}
+
+final class NavDivider extends NavEntry {
+  const NavDivider();
+}
+
+final class NavLink extends NavEntry {
+  final String title;
+  final String permalink;
+
+  const NavLink(this.title, this.permalink);
+}
+
+final class NavSection extends NavEntry {
+  final String title;
+  final List children;
+  final String? permalink;
+  final bool expanded;
+  final bool hiddenChildren;
+
+  const NavSection(
+    this.title,
+    this.children, {
+    this.permalink,
+    this.expanded = false,
+    this.hiddenChildren = false,
+  });
+}
diff --git a/site/lib/src/pages/custom_pages.dart b/site/lib/src/pages/custom_pages.dart
new file mode 100644
index 00000000000..c2c0d337ebc
--- /dev/null
+++ b/site/lib/src/pages/custom_pages.dart
@@ -0,0 +1,47 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:jaspr/server.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../components/pages/devtools_release_notes_index.dart';
+
+/// All pages that should be loaded from memory rather than
+/// from content loaded from the file system.
+List get allMemoryPages => [
+  _devtoolsReleasesIndex,
+];
+
+/// The `/f/devtools-releases.json` file that DevTools consumes.
+MemoryPage get _devtoolsReleasesIndex => MemoryPage.builder(
+  path: 'f/devtools-releases.json',
+  applyLayout: false,
+  keepSuffix: true,
+  initialData: {
+    'page': {
+      'title': 'DevTools release notes index',
+      'description': 'An index of DevTools release note Markdown files.',
+      'sitemap': false,
+    },
+  },
+  builder: (context) {
+    context.setHeader('Content-Type', 'application/json; charset=utf-8');
+
+    final releases = DevToolsReleaseNotesIndex.findDevToolsReleases(context);
+    final releaseData = {
+      'latest': releases.first.version.toString(),
+      'releases': {
+        for (final release in releases)
+          release.version.toString(): '/${release.page.path}',
+      },
+    };
+
+    const jsonEncoder = JsonEncoder.withIndent('  ');
+    context.setStatusCode(200, responseBody: jsonEncoder.convert(releaseData));
+
+    return const Component.empty();
+  },
+);
diff --git a/site/lib/src/pages/robots_txt.dart b/site/lib/src/pages/robots_txt.dart
new file mode 100644
index 00000000000..8fbfaea15a6
--- /dev/null
+++ b/site/lib/src/pages/robots_txt.dart
@@ -0,0 +1,54 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/server.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+
+import '../util.dart';
+
+/// The secondary output to configure to create
+/// a `robots.txt` file in the root directory.
+final class RobotsTxtOutput implements SecondaryOutput {
+  static final _indexPattern = RegExp(r'/?index\..*');
+
+  const RobotsTxtOutput();
+
+  @override
+  Pattern get pattern => _indexPattern;
+
+  @override
+  String createRoute(String _) => '/robots.txt';
+
+  @override
+  Component build(Page _) {
+    return Builder(
+      builder: (context) {
+        context.setHeader('Content-Type', 'text/plain; charset=utf-8');
+        final String textContent;
+        if (productionBuild) {
+          // If this is a production build, allow all bots to crawl the site.
+          textContent = '''
+User-agent: *
+Disallow:
+
+Sitemap: https://docs.flutter.dev/sitemap.xml
+''';
+        } else {
+          // If this isn't a production build, such as for staging on Firebase,
+          // don't allow bots to crawl or index the site.
+          // This helps prevent staged sites from showing up on search engines.
+          textContent = '''
+User-agent: linkcheck
+Disallow:
+
+User-agent: *
+Disallow: /
+''';
+        }
+        context.setStatusCode(200, responseBody: textContent);
+        return const Component.empty();
+      },
+    );
+  }
+}
diff --git a/site/lib/src/style_hash.dart b/site/lib/src/style_hash.dart
new file mode 100644
index 00000000000..9f473f0037b
--- /dev/null
+++ b/site/lib/src/style_hash.dart
@@ -0,0 +1,5 @@
+// Generated by docs_flutter_dev_site|stylesHashBuilder. Do not edit.
+// dart format off
+
+/// The generated hash of the `main.css` file.
+const generatedStylesHash = 'ugxj95DjrnBJ';
diff --git a/site/lib/src/templating/dash_template_engine.dart b/site/lib/src/templating/dash_template_engine.dart
new file mode 100644
index 00000000000..ed2a8e2dbe7
--- /dev/null
+++ b/site/lib/src/templating/dash_template_engine.dart
@@ -0,0 +1,97 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:collection/collection.dart';
+import 'package:jaspr_content/jaspr_content.dart';
+import 'package:liquify/liquify.dart';
+import 'package:path/path.dart' as path;
+
+import '../util.dart';
+
+/// A template engine for Jaspr Content that
+/// uses `package:liquify` to parse and render Liquid templates.
+final class DashTemplateEngine implements TemplateEngine {
+  DashTemplateEngine({required this.partialDirectoryPath});
+
+  /// The path to the directory containing partial files.
+  final String partialDirectoryPath;
+
+  /// The `package:liquify` environment to render templates with.
+  final Environment _renderEnvironment = Environment()
+    ..registerFilter('slugify', (value, _, _) {
+      if (value is! String) return value;
+
+      return slugify(value);
+    })
+    ..registerFilter('sortBy', (value, arguments, _) {
+      if (value is! List) return value;
+      final keyToSortBy = arguments[0] as Object;
+
+      // For now only support maps.
+      return value.cast>().sorted((left, right) {
+        final leftValue = left[keyToSortBy];
+        final rightValue = right[keyToSortBy];
+
+        if (leftValue == null && rightValue == null) return 0;
+        if (leftValue == null) return -1;
+        if (rightValue == null) return 1;
+
+        // Check if both values are Comparable and of the same type.
+        final int compareResult;
+        if (leftValue is Comparable &&
+            rightValue.runtimeType == leftValue.runtimeType) {
+          compareResult = leftValue.compareTo(rightValue);
+        } else {
+          // If not comparable or their types are different,
+          // treat them as equal.
+          compareResult = 0;
+        }
+
+        return compareResult;
+      });
+    });
+
+  @override
+  Future render(Page page, List pages) async {
+    if (page.data.page['skipTemplateRendering'] == true) {
+      return;
+    }
+
+    final template = Template.parse(
+      page.content,
+      data: {
+        ...page.data,
+        'pages': pages.map((page) => page.data.page).toList(growable: false),
+      },
+      root: _PartialResolver(
+        page: page,
+        partialDirectoryPath: partialDirectoryPath,
+      ),
+      environment: _renderEnvironment,
+    );
+
+    page.apply(content: await template.renderAsync());
+  }
+}
+
+class _PartialResolver implements Root {
+  _PartialResolver({required this.page, required this.partialDirectoryPath});
+
+  final Page page;
+  final String partialDirectoryPath;
+
+  @override
+  Source resolve(String relPath) {
+    final filePath = path.join(partialDirectoryPath, relPath);
+    final content = page.readPartialSync(filePath);
+    return Source(Uri.file(filePath), content, this);
+  }
+
+  @override
+  Future resolveAsync(String relPath) async {
+    final partialPath = path.join(partialDirectoryPath, relPath);
+    final partialContent = await page.readPartial(partialPath);
+    return Source(Uri.file(partialPath), partialContent, this);
+  }
+}
diff --git a/site/lib/src/util.dart b/site/lib/src/util.dart
new file mode 100644
index 00000000000..b4e2c607afd
--- /dev/null
+++ b/site/lib/src/util.dart
@@ -0,0 +1,178 @@
+// Copyright 2025 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:jaspr/jaspr.dart';
+import 'package:path/path.dart' as path;
+import 'package:universal_web/web.dart' as web;
+
+/// Whether this build of the site will be deployed to production.
+const productionBuild = bool.fromEnvironment('PRODUCTION');
+
+/// Path to the `/src` directory where site content is located.
+final siteSrcDirectoryPath = path.join('..', 'src');
+
+/// Split the specific [sourceString] into a list of Jaspr [Component]
+/// by adding a ``  element after each underscore.
+///
+/// This is useful for long IDs separated with underscores, such as lint names,
+/// that might otherwise break across lines in an undesirable way.
+List splitByUnderscore(String sourceString) {
+  final parts = sourceString.split('_');
+  final result = [];
+
+  for (var i = 0; i < parts.length; i++) {
+    result.add(text(parts[i]));
+
+    // Add a word break opportunity after each underscore,
+    // except for the final one.
+    if (i < parts.length - 1) {
+      result.add(const Component.text('_'));
+      result.add(const Component.element(tag: 'wbr'));
+    }
+  }
+
+  return result;
+}
+
+/// Converts the specified [text] into a standardized URL slug
+/// that can be used as the ID for headers and other anchors in HTML.
+String slugify(String text) => text
+    .toLowerCase()
+    .trim()
+    .replaceAll(_slugifyPunctuationToReplace, '-')
+    .replaceAll(_slugifyUnsupportedToRemove, '')
+    .replaceAll(_slugifyCharsToCombine, '-')
+    .replaceAll(_slugifyHyphenTrim, '');
+
+final RegExp _slugifyPunctuationToReplace = RegExp(r'[:._]');
+final RegExp _slugifyUnsupportedToRemove = RegExp(
+  r'[^\p{L}\p{N}\s:.-]',
+  unicode: true,
+);
+final RegExp _slugifyCharsToCombine = RegExp(r'[\s-]+');
+final RegExp _slugifyHyphenTrim = RegExp(r'^-+|-+$');
+
+final RegExp _attributePattern = RegExp(r'(\w+)="([^"]*)"');
+final RegExp _whitespacePattern = RegExp(r'\s+');
+final RegExp _wordPattern = RegExp(r'\S+(?:\s*|$)');
+final RegExp _trailingMarkdownLinkPattern = RegExp(r'(\[.+\]:\s*\S+\s*)+$');
+
+Map parseAttributes(String attributeString) {
+  final attributes = {};
+  final classes = [];
+
+  // Extract all key="value" pairs.
+  final keyValueMatches = _attributePattern.allMatches(attributeString);
+  for (final match in keyValueMatches) {
+    final key = match.group(1)!;
+    final value = match.group(2)!;
+    attributes[key] = value;
+  }
+
+  // Remove all key="value" pairs to process remaining tokens.
+  final remaining = attributeString.replaceAll(_attributePattern, '').trim();
+
+  // Split remaining content by whitespace to find IDs and classes.
+  final parts = remaining.split(_whitespacePattern);
+
+  for (final part in parts) {
+    if (part.isEmpty) continue;
+
+    if (part.startsWith('#')) {
+      attributes['id'] = part.substring(1);
+    } else if (part.startsWith('.')) {
+      classes.add(part.substring(1));
+    }
+  }
+
+  if (classes.isNotEmpty) {
+    attributes['class'] = classes.join(' ');
+  }
+
+  return attributes;
+}
+
+String truncateWords(String text, int maxWords) {
+  if (maxWords <= 0) {
+    return '';
+  }
+
+  final words = text.trim().split(_whitespacePattern);
+  if (words.length <= maxWords) {
+    return text;
+  }
+
+  final truncated = words.take(maxWords).join(' ');
+  return '$truncated...';
+}
+
+/// Truncates the given [text] to the specified number of words [maxWords],
+/// preserving all whitespace and line breaks, as well as any trailing Markdown
+/// link definitions at the end of the text.
+String truncateWordsMarkdown(String text, int maxWords) {
+  if (maxWords <= 0) {
+    return '';
+  }
+
+  final trailingLinks = _trailingMarkdownLinkPattern.firstMatch(text);
+  var endContent = '';
+
+  if (trailingLinks != null) {
+    text = text.substring(0, trailingLinks.start);
+    endContent = '\n${trailingLinks.group(0)!}';
+  }
+
+  final matches = _wordPattern.allMatches(text);
+  if (matches.length <= maxWords) {
+    return text + endContent;
+  }
+
+  final truncated = matches.map((m) => m.group(0)!).take(maxWords).join('');
+  return '$truncated...\n$endContent';
+}
+
+extension ListToClasses on List {
+  /// Convert a list of classes into a single class string
+  /// that can be added to an HTML element.
+  String get toClasses => join(' ');
+}
+
+enum OperatingSystem {
+  windows('Windows'),
+  macos('macOS'),
+  linux('Linux'),
+  chromeos('ChromeOS');
+
+  const OperatingSystem(this.label);
+  final String label;
+}
+
+/// Get the user's current operating system, or
+/// `null` if not of one "macos", "windows", "linux", or "chromeos".
+OperatingSystem? getOS() {
+  final userAgent = web.window.navigator.userAgent;
+  if (userAgent.contains('Mac')) {
+    // macOS or iPhone
+    return OperatingSystem.macos;
+  }
+
+  if (userAgent.contains('Win')) {
+    // Windows
+    return OperatingSystem.windows;
+  }
+
+  if ((userAgent.contains('Linux') || userAgent.contains('X11')) &&
+      !userAgent.contains('Android')) {
+    // Linux, but not Android
+    return OperatingSystem.linux;
+  }
+
+  if (userAgent.contains('CrOS')) {
+    // ChromeOS
+    return OperatingSystem.chromeos;
+  }
+
+  // Anything else
+  return null;
+}
diff --git a/site/pubspec.yaml b/site/pubspec.yaml
new file mode 100644
index 00000000000..bfb581f28ad
--- /dev/null
+++ b/site/pubspec.yaml
@@ -0,0 +1,41 @@
+name: docs_flutter_dev_site
+publish_to: none
+homepage: https://docs.flutter.dev
+
+resolution: workspace
+environment:
+  sdk: ^3.9.2
+
+dependencies:
+  build: ^4.0.2
+  collection: ^1.19.1
+  crypto: ^3.0.6
+  html: ^0.15.6
+  http: ^1.5.0
+  jaspr: ^0.21.6
+  jaspr_content: ^0.4.2
+  # Used as our template engine.
+  liquify: ^1.3.1
+  markdown: ^7.3.0
+  markdown_description_list: ^0.1.1
+  meta: ^1.17.0
+  # Used for syntax highlighting.
+  opal: ^0.2.0
+  path: ^1.9.1
+  pub_semver: ^2.2.0
+  universal_web: ^1.1.1+1
+
+dev_dependencies:
+  analysis_defaults:
+    git:
+      url: https://github.com/dart-lang/site-shared
+      path: pkgs/analysis_defaults
+      ref: f91ed8ecef6a0b31685804fe4102b25fda021460
+  build_runner: ^2.10.1
+  build_web_compilers: ^4.3.0
+  jaspr_builder: ^0.21.6
+  sass: ^1.93.2
+  sass_builder: ^2.4.0
+
+jaspr:
+  mode: static
diff --git a/site/web/assets/css/main.scss b/site/web/assets/css/main.scss
new file mode 100644
index 00000000000..ceffe5840a1
--- /dev/null
+++ b/site/web/assets/css/main.scss
@@ -0,0 +1 @@
+@forward 'package:docs_flutter_dev_site/_sass/_site.scss';
diff --git a/src/content/assets/images/404/dash_404.png b/site/web/assets/images/404/dash_404.png
similarity index 100%
rename from src/content/assets/images/404/dash_404.png
rename to site/web/assets/images/404/dash_404.png
diff --git a/src/content/assets/images/branding/dart/64.png b/site/web/assets/images/branding/dart/64.png
similarity index 100%
rename from src/content/assets/images/branding/dart/64.png
rename to site/web/assets/images/branding/dart/64.png
diff --git a/src/content/assets/images/branding/dart/logo.svg b/site/web/assets/images/branding/dart/logo.svg
similarity index 100%
rename from src/content/assets/images/branding/dart/logo.svg
rename to site/web/assets/images/branding/dart/logo.svg
diff --git a/src/content/assets/images/branding/flutter/icon/1080.png b/site/web/assets/images/branding/flutter/icon/1080.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/icon/1080.png
rename to site/web/assets/images/branding/flutter/icon/1080.png
diff --git a/src/content/assets/images/branding/flutter/icon/64.png b/site/web/assets/images/branding/flutter/icon/64.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/icon/64.png
rename to site/web/assets/images/branding/flutter/icon/64.png
diff --git a/src/content/assets/images/branding/flutter/icon/mono.svg b/site/web/assets/images/branding/flutter/icon/mono.svg
similarity index 100%
rename from src/content/assets/images/branding/flutter/icon/mono.svg
rename to site/web/assets/images/branding/flutter/icon/mono.svg
diff --git a/src/content/assets/images/branding/flutter/logo+text/horizontal/default.png b/site/web/assets/images/branding/flutter/logo+text/horizontal/default.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo+text/horizontal/default.png
rename to site/web/assets/images/branding/flutter/logo+text/horizontal/default.png
diff --git a/src/content/assets/images/branding/flutter/logo+text/horizontal/default.svg b/site/web/assets/images/branding/flutter/logo+text/horizontal/default.svg
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo+text/horizontal/default.svg
rename to site/web/assets/images/branding/flutter/logo+text/horizontal/default.svg
diff --git a/src/content/assets/images/branding/flutter/logo+text/horizontal/white.png b/site/web/assets/images/branding/flutter/logo+text/horizontal/white.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo+text/horizontal/white.png
rename to site/web/assets/images/branding/flutter/logo+text/horizontal/white.png
diff --git a/src/content/assets/images/branding/flutter/logo+text/horizontal/white.svg b/site/web/assets/images/branding/flutter/logo+text/horizontal/white.svg
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo+text/horizontal/white.svg
rename to site/web/assets/images/branding/flutter/logo+text/horizontal/white.svg
diff --git a/src/content/assets/images/branding/flutter/logo+text/vertical/default.png b/site/web/assets/images/branding/flutter/logo+text/vertical/default.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo+text/vertical/default.png
rename to site/web/assets/images/branding/flutter/logo+text/vertical/default.png
diff --git a/src/content/assets/images/branding/flutter/logo+text/vertical/default.svg b/site/web/assets/images/branding/flutter/logo+text/vertical/default.svg
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo+text/vertical/default.svg
rename to site/web/assets/images/branding/flutter/logo+text/vertical/default.svg
diff --git a/src/content/assets/images/branding/flutter/logo+text/vertical/white.png b/site/web/assets/images/branding/flutter/logo+text/vertical/white.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo+text/vertical/white.png
rename to site/web/assets/images/branding/flutter/logo+text/vertical/white.png
diff --git a/src/content/assets/images/branding/flutter/logo+text/vertical/white.svg b/site/web/assets/images/branding/flutter/logo+text/vertical/white.svg
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo+text/vertical/white.svg
rename to site/web/assets/images/branding/flutter/logo+text/vertical/white.svg
diff --git a/src/content/assets/images/branding/flutter/logo/1080.svg b/site/web/assets/images/branding/flutter/logo/1080.svg
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo/1080.svg
rename to site/web/assets/images/branding/flutter/logo/1080.svg
diff --git a/src/content/assets/images/branding/flutter/logo/default.svg b/site/web/assets/images/branding/flutter/logo/default.svg
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo/default.svg
rename to site/web/assets/images/branding/flutter/logo/default.svg
diff --git a/src/content/assets/images/branding/flutter/logo/flutter-lockup-small.png b/site/web/assets/images/branding/flutter/logo/flutter-lockup-small.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo/flutter-lockup-small.png
rename to site/web/assets/images/branding/flutter/logo/flutter-lockup-small.png
diff --git a/src/content/assets/images/branding/flutter/logo/flutter-lockup.png b/site/web/assets/images/branding/flutter/logo/flutter-lockup.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo/flutter-lockup.png
rename to site/web/assets/images/branding/flutter/logo/flutter-lockup.png
diff --git a/src/content/assets/images/branding/flutter/logo/flutter-logomark-1080px.png b/site/web/assets/images/branding/flutter/logo/flutter-logomark-1080px.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo/flutter-logomark-1080px.png
rename to site/web/assets/images/branding/flutter/logo/flutter-logomark-1080px.png
diff --git a/src/content/assets/images/branding/flutter/logo/flutter-logomark-320px.png b/site/web/assets/images/branding/flutter/logo/flutter-logomark-320px.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo/flutter-logomark-320px.png
rename to site/web/assets/images/branding/flutter/logo/flutter-logomark-320px.png
diff --git a/src/content/assets/images/branding/flutter/logo/flutter-mono-81x100.png b/site/web/assets/images/branding/flutter/logo/flutter-mono-81x100.png
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo/flutter-mono-81x100.png
rename to site/web/assets/images/branding/flutter/logo/flutter-mono-81x100.png
diff --git a/src/content/assets/images/branding/flutter/logo/square.svg b/site/web/assets/images/branding/flutter/logo/square.svg
similarity index 100%
rename from src/content/assets/images/branding/flutter/logo/square.svg
rename to site/web/assets/images/branding/flutter/logo/square.svg
diff --git a/src/content/assets/images/dash/BigDashAndLittleDash.png b/site/web/assets/images/dash/BigDashAndLittleDash.png
similarity index 100%
rename from src/content/assets/images/dash/BigDashAndLittleDash.png
rename to site/web/assets/images/dash/BigDashAndLittleDash.png
diff --git a/src/content/assets/images/dash/DartHummingbird.jpg b/site/web/assets/images/dash/DartHummingbird.jpg
similarity index 100%
rename from src/content/assets/images/dash/DartHummingbird.jpg
rename to site/web/assets/images/dash/DartHummingbird.jpg
diff --git a/src/content/assets/images/dash/Dash.png b/site/web/assets/images/dash/Dash.png
similarity index 100%
rename from src/content/assets/images/dash/Dash.png
rename to site/web/assets/images/dash/Dash.png
diff --git a/src/content/assets/images/dash/DashClawMachine.png b/site/web/assets/images/dash/DashClawMachine.png
similarity index 100%
rename from src/content/assets/images/dash/DashClawMachine.png
rename to site/web/assets/images/dash/DashClawMachine.png
diff --git a/src/content/assets/images/dash/Dashatars.png b/site/web/assets/images/dash/Dashatars.png
similarity index 100%
rename from src/content/assets/images/dash/Dashatars.png
rename to site/web/assets/images/dash/Dashatars.png
diff --git a/src/content/assets/images/dash/MegaDashChilling.png b/site/web/assets/images/dash/MegaDashChilling.png
similarity index 100%
rename from src/content/assets/images/dash/MegaDashChilling.png
rename to site/web/assets/images/dash/MegaDashChilling.png
diff --git a/src/content/assets/images/dash/NilayDashPuppet.png b/site/web/assets/images/dash/NilayDashPuppet.png
similarity index 100%
rename from src/content/assets/images/dash/NilayDashPuppet.png
rename to site/web/assets/images/dash/NilayDashPuppet.png
diff --git a/src/content/assets/images/dash/ShamsDashJacket.png b/site/web/assets/images/dash/ShamsDashJacket.png
similarity index 100%
rename from src/content/assets/images/dash/ShamsDashJacket.png
rename to site/web/assets/images/dash/ShamsDashJacket.png
diff --git a/src/content/assets/images/dash/dash-1.0.jpg b/site/web/assets/images/dash/dash-1.0.jpg
similarity index 100%
rename from src/content/assets/images/dash/dash-1.0.jpg
rename to site/web/assets/images/dash/dash-1.0.jpg
diff --git a/src/content/assets/images/dash/dash-conference-swag.jpg b/site/web/assets/images/dash/dash-conference-swag.jpg
similarity index 100%
rename from src/content/assets/images/dash/dash-conference-swag.jpg
rename to site/web/assets/images/dash/dash-conference-swag.jpg
diff --git a/src/content/assets/images/dash/dash-contribute.png b/site/web/assets/images/dash/dash-contribute.png
similarity index 100%
rename from src/content/assets/images/dash/dash-contribute.png
rename to site/web/assets/images/dash/dash-contribute.png
diff --git a/src/content/assets/images/dash/dash-fainting.gif b/site/web/assets/images/dash/dash-fainting.gif
similarity index 100%
rename from src/content/assets/images/dash/dash-fainting.gif
rename to site/web/assets/images/dash/dash-fainting.gif
diff --git a/src/content/assets/images/dash/dash-fainting.webp b/site/web/assets/images/dash/dash-fainting.webp
similarity index 100%
rename from src/content/assets/images/dash/dash-fainting.webp
rename to site/web/assets/images/dash/dash-fainting.webp
diff --git a/src/content/assets/images/dash/dash-prototypes.jpg b/site/web/assets/images/dash/dash-prototypes.jpg
similarity index 100%
rename from src/content/assets/images/dash/dash-prototypes.jpg
rename to site/web/assets/images/dash/dash-prototypes.jpg
diff --git a/src/content/assets/images/dash/dash-prototypes2.jpg b/site/web/assets/images/dash/dash-prototypes2.jpg
similarity index 100%
rename from src/content/assets/images/dash/dash-prototypes2.jpg
rename to site/web/assets/images/dash/dash-prototypes2.jpg
diff --git a/src/content/assets/images/dash/early-dash-sketches.png b/site/web/assets/images/dash/early-dash-sketches.png
similarity index 100%
rename from src/content/assets/images/dash/early-dash-sketches.png
rename to site/web/assets/images/dash/early-dash-sketches.png
diff --git a/src/content/assets/images/dash/early-dash-sketches2.jpg b/site/web/assets/images/dash/early-dash-sketches2.jpg
similarity index 100%
rename from src/content/assets/images/dash/early-dash-sketches2.jpg
rename to site/web/assets/images/dash/early-dash-sketches2.jpg
diff --git a/src/content/assets/images/dash/early-dash-sketches3.jpg b/site/web/assets/images/dash/early-dash-sketches3.jpg
similarity index 100%
rename from src/content/assets/images/dash/early-dash-sketches3.jpg
rename to site/web/assets/images/dash/early-dash-sketches3.jpg
diff --git a/src/content/assets/images/dash/early-dash-sketches4.jpg b/site/web/assets/images/dash/early-dash-sketches4.jpg
similarity index 100%
rename from src/content/assets/images/dash/early-dash-sketches4.jpg
rename to site/web/assets/images/dash/early-dash-sketches4.jpg
diff --git a/src/content/assets/images/dash/early-dash-sketches5.jpg b/site/web/assets/images/dash/early-dash-sketches5.jpg
similarity index 100%
rename from src/content/assets/images/dash/early-dash-sketches5.jpg
rename to site/web/assets/images/dash/early-dash-sketches5.jpg
diff --git a/src/content/assets/images/decorative/flutter-on-desktop.svg b/site/web/assets/images/decorative/flutter-on-desktop.svg
similarity index 100%
rename from src/content/assets/images/decorative/flutter-on-desktop.svg
rename to site/web/assets/images/decorative/flutter-on-desktop.svg
diff --git a/src/content/assets/images/decorative/flutter-on-phone.svg b/site/web/assets/images/decorative/flutter-on-phone.svg
similarity index 100%
rename from src/content/assets/images/decorative/flutter-on-phone.svg
rename to site/web/assets/images/decorative/flutter-on-phone.svg
diff --git a/src/content/assets/images/decorative/pointing-the-way.png b/site/web/assets/images/decorative/pointing-the-way.png
similarity index 100%
rename from src/content/assets/images/decorative/pointing-the-way.png
rename to site/web/assets/images/decorative/pointing-the-way.png
diff --git a/src/content/assets/images/decorative/up-to-date.png b/site/web/assets/images/decorative/up-to-date.png
similarity index 100%
rename from src/content/assets/images/decorative/up-to-date.png
rename to site/web/assets/images/decorative/up-to-date.png
diff --git a/src/content/assets/images/docs/LICENSE b/site/web/assets/images/docs/LICENSE
similarity index 100%
rename from src/content/assets/images/docs/LICENSE
rename to site/web/assets/images/docs/LICENSE
diff --git a/src/content/assets/images/docs/PlatformChannels.png b/site/web/assets/images/docs/PlatformChannels.png
similarity index 100%
rename from src/content/assets/images/docs/PlatformChannels.png
rename to site/web/assets/images/docs/PlatformChannels.png
diff --git a/src/content/assets/images/docs/a11y/app-large-fonts.png b/site/web/assets/images/docs/a11y/app-large-fonts.png
similarity index 100%
rename from src/content/assets/images/docs/a11y/app-large-fonts.png
rename to site/web/assets/images/docs/a11y/app-large-fonts.png
diff --git a/src/content/assets/images/docs/a11y/app-regular-fonts.png b/site/web/assets/images/docs/a11y/app-regular-fonts.png
similarity index 100%
rename from src/content/assets/images/docs/a11y/app-regular-fonts.png
rename to site/web/assets/images/docs/a11y/app-regular-fonts.png
diff --git a/site/web/assets/images/docs/a18n/app-large-fonts.png b/site/web/assets/images/docs/a18n/app-large-fonts.png
new file mode 100644
index 00000000000..c6debe6894b
Binary files /dev/null and b/site/web/assets/images/docs/a18n/app-large-fonts.png differ
diff --git a/site/web/assets/images/docs/a18n/app-regular-fonts.png b/site/web/assets/images/docs/a18n/app-regular-fonts.png
new file mode 100644
index 00000000000..b8e4927c025
Binary files /dev/null and b/site/web/assets/images/docs/a18n/app-regular-fonts.png differ
diff --git a/src/content/assets/images/docs/add-ads.png b/site/web/assets/images/docs/add-ads.png
similarity index 100%
rename from src/content/assets/images/docs/add-ads.png
rename to site/web/assets/images/docs/add-ads.png
diff --git a/src/content/assets/images/docs/add-in-app-purchases.png b/site/web/assets/images/docs/add-in-app-purchases.png
similarity index 100%
rename from src/content/assets/images/docs/add-in-app-purchases.png
rename to site/web/assets/images/docs/add-in-app-purchases.png
diff --git a/src/content/assets/images/docs/add-payments.png b/site/web/assets/images/docs/add-payments.png
similarity index 100%
rename from src/content/assets/images/docs/add-payments.png
rename to site/web/assets/images/docs/add-payments.png
diff --git a/src/content/assets/images/docs/ai-toolkit/accessing-edit-menu.png b/site/web/assets/images/docs/ai-toolkit/accessing-edit-menu.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/accessing-edit-menu.png
rename to site/web/assets/images/docs/ai-toolkit/accessing-edit-menu.png
diff --git a/src/content/assets/images/docs/ai-toolkit/add-recipe-button.png b/site/web/assets/images/docs/ai-toolkit/add-recipe-button.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/add-recipe-button.png
rename to site/web/assets/images/docs/ai-toolkit/add-recipe-button.png
diff --git a/src/content/assets/images/docs/ai-toolkit/ai-toolkit-app.png b/site/web/assets/images/docs/ai-toolkit/ai-toolkit-app.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/ai-toolkit-app.png
rename to site/web/assets/images/docs/ai-toolkit/ai-toolkit-app.png
diff --git a/src/content/assets/images/docs/ai-toolkit/apply-changes-decision.png b/site/web/assets/images/docs/ai-toolkit/apply-changes-decision.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/apply-changes-decision.png
rename to site/web/assets/images/docs/ai-toolkit/apply-changes-decision.png
diff --git a/src/content/assets/images/docs/ai-toolkit/chatbot-prompt.png b/site/web/assets/images/docs/ai-toolkit/chatbot-prompt.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/chatbot-prompt.png
rename to site/web/assets/images/docs/ai-toolkit/chatbot-prompt.png
diff --git a/src/content/assets/images/docs/ai-toolkit/copy-to-clipboard.png b/site/web/assets/images/docs/ai-toolkit/copy-to-clipboard.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/copy-to-clipboard.png
rename to site/web/assets/images/docs/ai-toolkit/copy-to-clipboard.png
diff --git a/src/content/assets/images/docs/ai-toolkit/cupertino-chat-app.png b/site/web/assets/images/docs/ai-toolkit/cupertino-chat-app.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/cupertino-chat-app.png
rename to site/web/assets/images/docs/ai-toolkit/cupertino-chat-app.png
diff --git a/src/content/assets/images/docs/ai-toolkit/demo-app.png b/site/web/assets/images/docs/ai-toolkit/demo-app.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/demo-app.png
rename to site/web/assets/images/docs/ai-toolkit/demo-app.png
diff --git a/src/content/assets/images/docs/ai-toolkit/desktop-enter-text.png b/site/web/assets/images/docs/ai-toolkit/desktop-enter-text.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/desktop-enter-text.png
rename to site/web/assets/images/docs/ai-toolkit/desktop-enter-text.png
diff --git a/src/content/assets/images/docs/ai-toolkit/desktop-pluto-convo.png b/site/web/assets/images/docs/ai-toolkit/desktop-pluto-convo.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/desktop-pluto-convo.png
rename to site/web/assets/images/docs/ai-toolkit/desktop-pluto-convo.png
diff --git a/src/content/assets/images/docs/ai-toolkit/download-from-gallery.png b/site/web/assets/images/docs/ai-toolkit/download-from-gallery.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/download-from-gallery.png
rename to site/web/assets/images/docs/ai-toolkit/download-from-gallery.png
diff --git a/src/content/assets/images/docs/ai-toolkit/enter-textfield.png b/site/web/assets/images/docs/ai-toolkit/enter-textfield.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/enter-textfield.png
rename to site/web/assets/images/docs/ai-toolkit/enter-textfield.png
diff --git a/src/content/assets/images/docs/ai-toolkit/enter-voice-into-textfield.png b/site/web/assets/images/docs/ai-toolkit/enter-voice-into-textfield.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/enter-voice-into-textfield.png
rename to site/web/assets/images/docs/ai-toolkit/enter-voice-into-textfield.png
diff --git a/src/content/assets/images/docs/ai-toolkit/example-of-suggested-prompts.png b/site/web/assets/images/docs/ai-toolkit/example-of-suggested-prompts.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/example-of-suggested-prompts.png
rename to site/web/assets/images/docs/ai-toolkit/example-of-suggested-prompts.png
diff --git a/src/content/assets/images/docs/ai-toolkit/example-of-welcome-message.png b/site/web/assets/images/docs/ai-toolkit/example-of-welcome-message.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/example-of-welcome-message.png
rename to site/web/assets/images/docs/ai-toolkit/example-of-welcome-message.png
diff --git a/src/content/assets/images/docs/ai-toolkit/how-to-edit-prompt.png b/site/web/assets/images/docs/ai-toolkit/how-to-edit-prompt.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/how-to-edit-prompt.png
rename to site/web/assets/images/docs/ai-toolkit/how-to-edit-prompt.png
diff --git a/src/content/assets/images/docs/ai-toolkit/how-to-exit-editing-mode.png b/site/web/assets/images/docs/ai-toolkit/how-to-exit-editing-mode.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/how-to-exit-editing-mode.png
rename to site/web/assets/images/docs/ai-toolkit/how-to-exit-editing-mode.png
diff --git a/src/content/assets/images/docs/ai-toolkit/image-thumbnails.png b/site/web/assets/images/docs/ai-toolkit/image-thumbnails.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/image-thumbnails.png
rename to site/web/assets/images/docs/ai-toolkit/image-thumbnails.png
diff --git a/src/content/assets/images/docs/ai-toolkit/image-zoom.png b/site/web/assets/images/docs/ai-toolkit/image-zoom.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/image-zoom.png
rename to site/web/assets/images/docs/ai-toolkit/image-zoom.png
diff --git a/src/content/assets/images/docs/ai-toolkit/long-tap-choose-copy.png b/site/web/assets/images/docs/ai-toolkit/long-tap-choose-copy.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/long-tap-choose-copy.png
rename to site/web/assets/images/docs/ai-toolkit/long-tap-choose-copy.png
diff --git a/src/content/assets/images/docs/ai-toolkit/mobile-enter-text.png b/site/web/assets/images/docs/ai-toolkit/mobile-enter-text.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/mobile-enter-text.png
rename to site/web/assets/images/docs/ai-toolkit/mobile-enter-text.png
diff --git a/src/content/assets/images/docs/ai-toolkit/mobile-pluto-convo.png b/site/web/assets/images/docs/ai-toolkit/mobile-pluto-convo.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/mobile-pluto-convo.png
rename to site/web/assets/images/docs/ai-toolkit/mobile-pluto-convo.png
diff --git a/src/content/assets/images/docs/ai-toolkit/multi-media-icons.png b/site/web/assets/images/docs/ai-toolkit/multi-media-icons.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/multi-media-icons.png
rename to site/web/assets/images/docs/ai-toolkit/multi-media-icons.png
diff --git a/src/content/assets/images/docs/ai-toolkit/multi-media-testing-testing.png b/site/web/assets/images/docs/ai-toolkit/multi-media-testing-testing.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/multi-media-testing-testing.png
rename to site/web/assets/images/docs/ai-toolkit/multi-media-testing-testing.png
diff --git a/src/content/assets/images/docs/ai-toolkit/selfie.png b/site/web/assets/images/docs/ai-toolkit/selfie.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/selfie.png
rename to site/web/assets/images/docs/ai-toolkit/selfie.png
diff --git a/src/content/assets/images/docs/ai-toolkit/setting-food-preferences.png b/site/web/assets/images/docs/ai-toolkit/setting-food-preferences.png
similarity index 100%
rename from src/content/assets/images/docs/ai-toolkit/setting-food-preferences.png
rename to site/web/assets/images/docs/ai-toolkit/setting-food-preferences.png
diff --git a/src/content/assets/images/docs/androidx/do_androidx_refactor.png b/site/web/assets/images/docs/androidx/do_androidx_refactor.png
similarity index 100%
rename from src/content/assets/images/docs/androidx/do_androidx_refactor.png
rename to site/web/assets/images/docs/androidx/do_androidx_refactor.png
diff --git a/src/content/assets/images/docs/androidx/migrate_prompt.png b/site/web/assets/images/docs/androidx/migrate_prompt.png
similarity index 100%
rename from src/content/assets/images/docs/androidx/migrate_prompt.png
rename to site/web/assets/images/docs/androidx/migrate_prompt.png
diff --git a/src/content/assets/images/docs/app-anatomy.svg b/site/web/assets/images/docs/app-anatomy.svg
similarity index 100%
rename from src/content/assets/images/docs/app-anatomy.svg
rename to site/web/assets/images/docs/app-anatomy.svg
diff --git a/src/content/assets/images/docs/app-architecture/case-study/booking_screen.png b/site/web/assets/images/docs/app-architecture/case-study/booking_screen.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/booking_screen.png
rename to site/web/assets/images/docs/app-architecture/case-study/booking_screen.png
diff --git a/src/content/assets/images/docs/app-architecture/case-study/date_select_screen.png b/site/web/assets/images/docs/app-architecture/case-study/date_select_screen.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/date_select_screen.png
rename to site/web/assets/images/docs/app-architecture/case-study/date_select_screen.png
diff --git a/src/content/assets/images/docs/app-architecture/case-study/dismissible.webp b/site/web/assets/images/docs/app-architecture/case-study/dismissible.webp
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/dismissible.webp
rename to site/web/assets/images/docs/app-architecture/case-study/dismissible.webp
diff --git a/src/content/assets/images/docs/app-architecture/case-study/home_screen.png b/site/web/assets/images/docs/app-architecture/case-study/home_screen.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/home_screen.png
rename to site/web/assets/images/docs/app-architecture/case-study/home_screen.png
diff --git a/src/content/assets/images/docs/app-architecture/case-study/mvvm-case-study-services-architecture.png b/site/web/assets/images/docs/app-architecture/case-study/mvvm-case-study-services-architecture.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/mvvm-case-study-services-architecture.png
rename to site/web/assets/images/docs/app-architecture/case-study/mvvm-case-study-services-architecture.png
diff --git a/src/content/assets/images/docs/app-architecture/case-study/mvvm-case-study-ui-layer-highlighted.png b/site/web/assets/images/docs/app-architecture/case-study/mvvm-case-study-ui-layer-highlighted.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/mvvm-case-study-ui-layer-highlighted.png
rename to site/web/assets/images/docs/app-architecture/case-study/mvvm-case-study-ui-layer-highlighted.png
diff --git a/src/content/assets/images/docs/app-architecture/case-study/mvvm-case-study-ui-state-highlighted.png b/site/web/assets/images/docs/app-architecture/case-study/mvvm-case-study-ui-state-highlighted.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/mvvm-case-study-ui-state-highlighted.png
rename to site/web/assets/images/docs/app-architecture/case-study/mvvm-case-study-ui-state-highlighted.png
diff --git a/src/content/assets/images/docs/app-architecture/case-study/mvvm-case-study-update-ui-steps.png b/site/web/assets/images/docs/app-architecture/case-study/mvvm-case-study-update-ui-steps.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/mvvm-case-study-update-ui-steps.png
rename to site/web/assets/images/docs/app-architecture/case-study/mvvm-case-study-update-ui-steps.png
diff --git a/src/content/assets/images/docs/app-architecture/case-study/search_form_screen.png b/site/web/assets/images/docs/app-architecture/case-study/search_form_screen.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/search_form_screen.png
rename to site/web/assets/images/docs/app-architecture/case-study/search_form_screen.png
diff --git a/src/content/assets/images/docs/app-architecture/case-study/splash_screen.png b/site/web/assets/images/docs/app-architecture/case-study/splash_screen.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/case-study/splash_screen.png
rename to site/web/assets/images/docs/app-architecture/case-study/splash_screen.png
diff --git a/src/content/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-UDF.png b/site/web/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-UDF.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-UDF.png
rename to site/web/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-UDF.png
diff --git a/src/content/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-icons.png b/site/web/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-icons.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-icons.png
rename to site/web/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-icons.png
diff --git a/src/content/assets/images/docs/app-architecture/common-architecture-concepts/ui-f-state.png b/site/web/assets/images/docs/app-architecture/common-architecture-concepts/ui-f-state.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/common-architecture-concepts/ui-f-state.png
rename to site/web/assets/images/docs/app-architecture/common-architecture-concepts/ui-f-state.png
diff --git a/src/content/assets/images/docs/app-architecture/design-patterns/command-icon.svg b/site/web/assets/images/docs/app-architecture/design-patterns/command-icon.svg
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/design-patterns/command-icon.svg
rename to site/web/assets/images/docs/app-architecture/design-patterns/command-icon.svg
diff --git a/src/content/assets/images/docs/app-architecture/design-patterns/kv-store-icon.svg b/site/web/assets/images/docs/app-architecture/design-patterns/kv-store-icon.svg
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/design-patterns/kv-store-icon.svg
rename to site/web/assets/images/docs/app-architecture/design-patterns/kv-store-icon.svg
diff --git a/src/content/assets/images/docs/app-architecture/design-patterns/offline-first-icon.svg b/site/web/assets/images/docs/app-architecture/design-patterns/offline-first-icon.svg
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/design-patterns/offline-first-icon.svg
rename to site/web/assets/images/docs/app-architecture/design-patterns/offline-first-icon.svg
diff --git a/src/content/assets/images/docs/app-architecture/design-patterns/optimistic-state-icon.svg b/site/web/assets/images/docs/app-architecture/design-patterns/optimistic-state-icon.svg
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/design-patterns/optimistic-state-icon.svg
rename to site/web/assets/images/docs/app-architecture/design-patterns/optimistic-state-icon.svg
diff --git a/src/content/assets/images/docs/app-architecture/design-patterns/result-icon.svg b/site/web/assets/images/docs/app-architecture/design-patterns/result-icon.svg
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/design-patterns/result-icon.svg
rename to site/web/assets/images/docs/app-architecture/design-patterns/result-icon.svg
diff --git a/src/content/assets/images/docs/app-architecture/design-patterns/sql-icon.svg b/site/web/assets/images/docs/app-architecture/design-patterns/sql-icon.svg
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/design-patterns/sql-icon.svg
rename to site/web/assets/images/docs/app-architecture/design-patterns/sql-icon.svg
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-example.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-example.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-example.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-example.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Data-highlighted.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Data-highlighted.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Data-highlighted.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Data-highlighted.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Repository-highlighted.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Repository-highlighted.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Repository-highlighted.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Repository-highlighted.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Service-highlighted.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Service-highlighted.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Service-highlighted.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-Service-highlighted.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-UI-highlighted.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-UI-highlighted.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-UI-highlighted.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-UI-highlighted.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-View-highlighted.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-View-highlighted.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-View-highlighted.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-View-highlighted.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-ViewModel-highlighted.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-ViewModel-highlighted.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-ViewModel-highlighted.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-ViewModel-highlighted.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-with-logic-layer.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-with-logic-layer.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified-with-logic-layer.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified-with-logic-layer.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified.png b/site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/feature-architecture-simplified.png
rename to site/web/assets/images/docs/app-architecture/guide/feature-architecture-simplified.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/mvvm-intro-with-domain-layer.png b/site/web/assets/images/docs/app-architecture/guide/mvvm-intro-with-domain-layer.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/mvvm-intro-with-domain-layer.png
rename to site/web/assets/images/docs/app-architecture/guide/mvvm-intro-with-domain-layer.png
diff --git a/src/content/assets/images/docs/app-architecture/guide/mvvm-intro-with-layers.png b/site/web/assets/images/docs/app-architecture/guide/mvvm-intro-with-layers.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/guide/mvvm-intro-with-layers.png
rename to site/web/assets/images/docs/app-architecture/guide/mvvm-intro-with-layers.png
diff --git a/src/content/assets/images/docs/app-architecture/hero-image.png b/site/web/assets/images/docs/app-architecture/hero-image.png
similarity index 100%
rename from src/content/assets/images/docs/app-architecture/hero-image.png
rename to site/web/assets/images/docs/app-architecture/hero-image.png
diff --git a/src/content/assets/images/docs/arch-overview/archdiagram.png b/site/web/assets/images/docs/arch-overview/archdiagram.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/archdiagram.png
rename to site/web/assets/images/docs/arch-overview/archdiagram.png
diff --git a/src/content/assets/images/docs/arch-overview/color-picker.png b/site/web/assets/images/docs/arch-overview/color-picker.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/color-picker.png
rename to site/web/assets/images/docs/arch-overview/color-picker.png
diff --git a/src/content/assets/images/docs/arch-overview/constraints-sizes.png b/site/web/assets/images/docs/arch-overview/constraints-sizes.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/constraints-sizes.png
rename to site/web/assets/images/docs/arch-overview/constraints-sizes.png
diff --git a/src/content/assets/images/docs/arch-overview/inherited-widget.png b/site/web/assets/images/docs/arch-overview/inherited-widget.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/inherited-widget.png
rename to site/web/assets/images/docs/arch-overview/inherited-widget.png
diff --git a/src/content/assets/images/docs/arch-overview/platform-channels.png b/site/web/assets/images/docs/arch-overview/platform-channels.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/platform-channels.png
rename to site/web/assets/images/docs/arch-overview/platform-channels.png
diff --git a/src/content/assets/images/docs/arch-overview/render-pipeline.png b/site/web/assets/images/docs/arch-overview/render-pipeline.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/render-pipeline.png
rename to site/web/assets/images/docs/arch-overview/render-pipeline.png
diff --git a/src/content/assets/images/docs/arch-overview/trees.png b/site/web/assets/images/docs/arch-overview/trees.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/trees.png
rename to site/web/assets/images/docs/arch-overview/trees.png
diff --git a/src/content/assets/images/docs/arch-overview/web-framework-diagram.png b/site/web/assets/images/docs/arch-overview/web-framework-diagram.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/web-framework-diagram.png
rename to site/web/assets/images/docs/arch-overview/web-framework-diagram.png
diff --git a/src/content/assets/images/docs/arch-overview/widget-element.png b/site/web/assets/images/docs/arch-overview/widget-element.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/widget-element.png
rename to site/web/assets/images/docs/arch-overview/widget-element.png
diff --git a/src/content/assets/images/docs/arch-overview/widgets.png b/site/web/assets/images/docs/arch-overview/widgets.png
similarity index 100%
rename from src/content/assets/images/docs/arch-overview/widgets.png
rename to site/web/assets/images/docs/arch-overview/widgets.png
diff --git a/src/content/assets/images/docs/assets-and-images/android-icon-path.png b/site/web/assets/images/docs/assets-and-images/android-icon-path.png
similarity index 100%
rename from src/content/assets/images/docs/assets-and-images/android-icon-path.png
rename to site/web/assets/images/docs/assets-and-images/android-icon-path.png
diff --git a/src/content/assets/images/docs/assets-and-images/icon.png b/site/web/assets/images/docs/assets-and-images/icon.png
similarity index 100%
rename from src/content/assets/images/docs/assets-and-images/icon.png
rename to site/web/assets/images/docs/assets-and-images/icon.png
diff --git a/src/content/assets/images/docs/assets-and-images/ios-icon-path.png b/site/web/assets/images/docs/assets-and-images/ios-icon-path.png
similarity index 100%
rename from src/content/assets/images/docs/assets-and-images/ios-icon-path.png
rename to site/web/assets/images/docs/assets-and-images/ios-icon-path.png
diff --git a/src/content/assets/images/docs/assets-and-images/ios-launchscreen-xcode.png b/site/web/assets/images/docs/assets-and-images/ios-launchscreen-xcode.png
similarity index 100%
rename from src/content/assets/images/docs/assets-and-images/ios-launchscreen-xcode.png
rename to site/web/assets/images/docs/assets-and-images/ios-launchscreen-xcode.png
diff --git a/src/content/assets/images/docs/assets-and-images/launch-screen.png b/site/web/assets/images/docs/assets-and-images/launch-screen.png
similarity index 100%
rename from src/content/assets/images/docs/assets-and-images/launch-screen.png
rename to site/web/assets/images/docs/assets-and-images/launch-screen.png
diff --git a/src/content/assets/images/docs/brand-svg/chromeos.svg b/site/web/assets/images/docs/brand-svg/chromeos.svg
similarity index 100%
rename from src/content/assets/images/docs/brand-svg/chromeos.svg
rename to site/web/assets/images/docs/brand-svg/chromeos.svg
diff --git a/src/content/assets/images/docs/brand-svg/linux.svg b/site/web/assets/images/docs/brand-svg/linux.svg
similarity index 100%
rename from src/content/assets/images/docs/brand-svg/linux.svg
rename to site/web/assets/images/docs/brand-svg/linux.svg
diff --git a/src/content/assets/images/docs/brand-svg/macos-bug.svg b/site/web/assets/images/docs/brand-svg/macos-bug.svg
similarity index 100%
rename from src/content/assets/images/docs/brand-svg/macos-bug.svg
rename to site/web/assets/images/docs/brand-svg/macos-bug.svg
diff --git a/src/content/assets/images/docs/brand-svg/macos.svg b/site/web/assets/images/docs/brand-svg/macos.svg
similarity index 100%
rename from src/content/assets/images/docs/brand-svg/macos.svg
rename to site/web/assets/images/docs/brand-svg/macos.svg
diff --git a/src/content/assets/images/docs/brand-svg/windows-bug.svg b/site/web/assets/images/docs/brand-svg/windows-bug.svg
similarity index 100%
rename from src/content/assets/images/docs/brand-svg/windows-bug.svg
rename to site/web/assets/images/docs/brand-svg/windows-bug.svg
diff --git a/src/content/assets/images/docs/brand-svg/windows.svg b/site/web/assets/images/docs/brand-svg/windows.svg
similarity index 100%
rename from src/content/assets/images/docs/brand-svg/windows.svg
rename to site/web/assets/images/docs/brand-svg/windows.svg
diff --git a/src/content/assets/images/docs/breaking-changes/baseline.gif b/site/web/assets/images/docs/breaking-changes/baseline.gif
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/baseline.gif
rename to site/web/assets/images/docs/breaking-changes/baseline.gif
diff --git a/src/content/assets/images/docs/breaking-changes/material.floating_action_button_test.clip_masterImage.png b/site/web/assets/images/docs/breaking-changes/material.floating_action_button_test.clip_masterImage.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/material.floating_action_button_test.clip_masterImage.png
rename to site/web/assets/images/docs/breaking-changes/material.floating_action_button_test.clip_masterImage.png
diff --git a/src/content/assets/images/docs/breaking-changes/material.floating_action_button_test.clip_testImage.png b/site/web/assets/images/docs/breaking-changes/material.floating_action_button_test.clip_testImage.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/material.floating_action_button_test.clip_testImage.png
rename to site/web/assets/images/docs/breaking-changes/material.floating_action_button_test.clip_testImage.png
diff --git a/src/content/assets/images/docs/breaking-changes/material.ink_sparkle.bottom_right.0_masterImage.png b/site/web/assets/images/docs/breaking-changes/material.ink_sparkle.bottom_right.0_masterImage.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/material.ink_sparkle.bottom_right.0_masterImage.png
rename to site/web/assets/images/docs/breaking-changes/material.ink_sparkle.bottom_right.0_masterImage.png
diff --git a/src/content/assets/images/docs/breaking-changes/material.ink_sparkle.bottom_right.0_testImage.png b/site/web/assets/images/docs/breaking-changes/material.ink_sparkle.bottom_right.0_testImage.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/material.ink_sparkle.bottom_right.0_testImage.png
rename to site/web/assets/images/docs/breaking-changes/material.ink_sparkle.bottom_right.0_testImage.png
diff --git a/src/content/assets/images/docs/breaking-changes/not_def.gif b/site/web/assets/images/docs/breaking-changes/not_def.gif
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/not_def.gif
rename to site/web/assets/images/docs/breaking-changes/not_def.gif
diff --git a/src/content/assets/images/docs/breaking-changes/uiscene-new-file.png b/site/web/assets/images/docs/breaking-changes/uiscene-new-file.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/uiscene-new-file.png
rename to site/web/assets/images/docs/breaking-changes/uiscene-new-file.png
diff --git a/src/content/assets/images/docs/breaking-changes/uiscenedelegate-plist.png b/site/web/assets/images/docs/breaking-changes/uiscenedelegate-plist.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/uiscenedelegate-plist.png
rename to site/web/assets/images/docs/breaking-changes/uiscenedelegate-plist.png
diff --git a/src/content/assets/images/docs/breaking-changes/uiscenedelegate-swiftui-info-plist.png b/site/web/assets/images/docs/breaking-changes/uiscenedelegate-swiftui-info-plist.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/uiscenedelegate-swiftui-info-plist.png
rename to site/web/assets/images/docs/breaking-changes/uiscenedelegate-swiftui-info-plist.png
diff --git a/src/content/assets/images/docs/breaking-changes/underline.gif b/site/web/assets/images/docs/breaking-changes/underline.gif
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/underline.gif
rename to site/web/assets/images/docs/breaking-changes/underline.gif
diff --git a/src/content/assets/images/docs/breaking-changes/widgets.text_golden.Decoration.1_masterImage.png b/site/web/assets/images/docs/breaking-changes/widgets.text_golden.Decoration.1_masterImage.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/widgets.text_golden.Decoration.1_masterImage.png
rename to site/web/assets/images/docs/breaking-changes/widgets.text_golden.Decoration.1_masterImage.png
diff --git a/src/content/assets/images/docs/breaking-changes/widgets.text_golden.Decoration.1_testImage.png b/site/web/assets/images/docs/breaking-changes/widgets.text_golden.Decoration.1_testImage.png
similarity index 100%
rename from src/content/assets/images/docs/breaking-changes/widgets.text_golden.Decoration.1_testImage.png
rename to site/web/assets/images/docs/breaking-changes/widgets.text_golden.Decoration.1_testImage.png
diff --git a/src/content/assets/images/docs/catalog-widget-placeholder.png b/site/web/assets/images/docs/catalog-widget-placeholder.png
similarity index 100%
rename from src/content/assets/images/docs/catalog-widget-placeholder.png
rename to site/web/assets/images/docs/catalog-widget-placeholder.png
diff --git a/src/content/assets/images/docs/cd/android.png b/site/web/assets/images/docs/cd/android.png
similarity index 100%
rename from src/content/assets/images/docs/cd/android.png
rename to site/web/assets/images/docs/cd/android.png
diff --git a/src/content/assets/images/docs/cd/ios.png b/site/web/assets/images/docs/cd/ios.png
similarity index 100%
rename from src/content/assets/images/docs/cd/ios.png
rename to site/web/assets/images/docs/cd/ios.png
diff --git a/src/content/assets/images/docs/cookbook/ads-ad-unit-id.png b/site/web/assets/images/docs/cookbook/ads-ad-unit-id.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/ads-ad-unit-id.png
rename to site/web/assets/images/docs/cookbook/ads-ad-unit-id.png
diff --git a/src/content/assets/images/docs/cookbook/ads-ad-unit.png b/site/web/assets/images/docs/cookbook/ads-ad-unit.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/ads-ad-unit.png
rename to site/web/assets/images/docs/cookbook/ads-ad-unit.png
diff --git a/src/content/assets/images/docs/cookbook/ads-app-id.png b/site/web/assets/images/docs/cookbook/ads-app-id.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/ads-app-id.png
rename to site/web/assets/images/docs/cookbook/ads-app-id.png
diff --git a/src/content/assets/images/docs/cookbook/ads-device.jpg b/site/web/assets/images/docs/cookbook/ads-device.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/ads-device.jpg
rename to site/web/assets/images/docs/cookbook/ads-device.jpg
diff --git a/src/content/assets/images/docs/cookbook/ads-multidex.png b/site/web/assets/images/docs/cookbook/ads-multidex.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/ads-multidex.png
rename to site/web/assets/images/docs/cookbook/ads-multidex.png
diff --git a/src/content/assets/images/docs/cookbook/animated-container.webp b/site/web/assets/images/docs/cookbook/animated-container.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/animated-container.webp
rename to site/web/assets/images/docs/cookbook/animated-container.webp
diff --git a/src/content/assets/images/docs/cookbook/animation-physics-card-drag.webp b/site/web/assets/images/docs/cookbook/animation-physics-card-drag.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/animation-physics-card-drag.webp
rename to site/web/assets/images/docs/cookbook/animation-physics-card-drag.webp
diff --git a/src/content/assets/images/docs/cookbook/app-store-add-app-button.png b/site/web/assets/images/docs/cookbook/app-store-add-app-button.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/app-store-add-app-button.png
rename to site/web/assets/images/docs/cookbook/app-store-add-app-button.png
diff --git a/src/content/assets/images/docs/cookbook/architecture/optimistic-state.png b/site/web/assets/images/docs/cookbook/architecture/optimistic-state.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/architecture/optimistic-state.png
rename to site/web/assets/images/docs/cookbook/architecture/optimistic-state.png
diff --git a/src/content/assets/images/docs/cookbook/architecture/optimistic-state.webp b/site/web/assets/images/docs/cookbook/architecture/optimistic-state.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/architecture/optimistic-state.webp
rename to site/web/assets/images/docs/cookbook/architecture/optimistic-state.webp
diff --git a/src/content/assets/images/docs/cookbook/architecture/todo_app_dark.png b/site/web/assets/images/docs/cookbook/architecture/todo_app_dark.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/architecture/todo_app_dark.png
rename to site/web/assets/images/docs/cookbook/architecture/todo_app_dark.png
diff --git a/src/content/assets/images/docs/cookbook/architecture/todo_app_light.png b/site/web/assets/images/docs/cookbook/architecture/todo_app_light.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/architecture/todo_app_light.png
rename to site/web/assets/images/docs/cookbook/architecture/todo_app_light.png
diff --git a/src/content/assets/images/docs/cookbook/basic-list.png b/site/web/assets/images/docs/cookbook/basic-list.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/basic-list.png
rename to site/web/assets/images/docs/cookbook/basic-list.png
diff --git a/src/content/assets/images/docs/cookbook/dismissible.webp b/site/web/assets/images/docs/cookbook/dismissible.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/dismissible.webp
rename to site/web/assets/images/docs/cookbook/dismissible.webp
diff --git a/src/content/assets/images/docs/cookbook/drawer.png b/site/web/assets/images/docs/cookbook/drawer.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/drawer.png
rename to site/web/assets/images/docs/cookbook/drawer.png
diff --git a/src/content/assets/images/docs/cookbook/effects/DownloadButton.webp b/site/web/assets/images/docs/cookbook/effects/DownloadButton.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/DownloadButton.webp
rename to site/web/assets/images/docs/cookbook/effects/DownloadButton.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/DragAUIElement.webp b/site/web/assets/images/docs/cookbook/effects/DragAUIElement.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/DragAUIElement.webp
rename to site/web/assets/images/docs/cookbook/effects/DragAUIElement.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/ExpandingFAB.webp b/site/web/assets/images/docs/cookbook/effects/ExpandingFAB.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/ExpandingFAB.webp
rename to site/web/assets/images/docs/cookbook/effects/ExpandingFAB.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/GradientBubbles.webp b/site/web/assets/images/docs/cookbook/effects/GradientBubbles.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/GradientBubbles.webp
rename to site/web/assets/images/docs/cookbook/effects/GradientBubbles.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/LoadingShimmer.webp b/site/web/assets/images/docs/cookbook/effects/LoadingShimmer.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/LoadingShimmer.webp
rename to site/web/assets/images/docs/cookbook/effects/LoadingShimmer.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/NestedNavigator.webp b/site/web/assets/images/docs/cookbook/effects/NestedNavigator.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/NestedNavigator.webp
rename to site/web/assets/images/docs/cookbook/effects/NestedNavigator.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/ParallaxScrolling.webp b/site/web/assets/images/docs/cookbook/effects/ParallaxScrolling.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/ParallaxScrolling.webp
rename to site/web/assets/images/docs/cookbook/effects/ParallaxScrolling.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/StaggeredMenuAnimation.webp b/site/web/assets/images/docs/cookbook/effects/StaggeredMenuAnimation.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/StaggeredMenuAnimation.webp
rename to site/web/assets/images/docs/cookbook/effects/StaggeredMenuAnimation.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/TimingDiagram.png b/site/web/assets/images/docs/cookbook/effects/TimingDiagram.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/TimingDiagram.png
rename to site/web/assets/images/docs/cookbook/effects/TimingDiagram.png
diff --git a/src/content/assets/images/docs/cookbook/effects/TypingIndicator.webp b/site/web/assets/images/docs/cookbook/effects/TypingIndicator.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/TypingIndicator.webp
rename to site/web/assets/images/docs/cookbook/effects/TypingIndicator.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/UILoadingAnimation.webp b/site/web/assets/images/docs/cookbook/effects/UILoadingAnimation.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/UILoadingAnimation.webp
rename to site/web/assets/images/docs/cookbook/effects/UILoadingAnimation.webp
diff --git a/src/content/assets/images/docs/cookbook/effects/_README.md b/site/web/assets/images/docs/cookbook/effects/_README.md
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/_README.md
rename to site/web/assets/images/docs/cookbook/effects/_README.md
diff --git a/src/content/assets/images/docs/cookbook/effects/app-hero/app-hero.jpg b/site/web/assets/images/docs/cookbook/effects/app-hero/app-hero.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/app-hero/app-hero.jpg
rename to site/web/assets/images/docs/cookbook/effects/app-hero/app-hero.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/instagram-buttons/millennial-dude.jpg b/site/web/assets/images/docs/cookbook/effects/instagram-buttons/millennial-dude.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/instagram-buttons/millennial-dude.jpg
rename to site/web/assets/images/docs/cookbook/effects/instagram-buttons/millennial-dude.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/instagram-buttons/millennial-texture.jpg b/site/web/assets/images/docs/cookbook/effects/instagram-buttons/millennial-texture.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/instagram-buttons/millennial-texture.jpg
rename to site/web/assets/images/docs/cookbook/effects/instagram-buttons/millennial-texture.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/parallax/00-header.jpg b/site/web/assets/images/docs/cookbook/effects/parallax/00-header.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/parallax/00-header.jpg
rename to site/web/assets/images/docs/cookbook/effects/parallax/00-header.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/parallax/01-mount-rushmore.jpg b/site/web/assets/images/docs/cookbook/effects/parallax/01-mount-rushmore.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/parallax/01-mount-rushmore.jpg
rename to site/web/assets/images/docs/cookbook/effects/parallax/01-mount-rushmore.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/parallax/02-singapore.jpg b/site/web/assets/images/docs/cookbook/effects/parallax/02-singapore.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/parallax/02-singapore.jpg
rename to site/web/assets/images/docs/cookbook/effects/parallax/02-singapore.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/parallax/03-machu-picchu.jpg b/site/web/assets/images/docs/cookbook/effects/parallax/03-machu-picchu.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/parallax/03-machu-picchu.jpg
rename to site/web/assets/images/docs/cookbook/effects/parallax/03-machu-picchu.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/parallax/04-vitznau.jpg b/site/web/assets/images/docs/cookbook/effects/parallax/04-vitznau.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/parallax/04-vitznau.jpg
rename to site/web/assets/images/docs/cookbook/effects/parallax/04-vitznau.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/parallax/05-bali.jpg b/site/web/assets/images/docs/cookbook/effects/parallax/05-bali.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/parallax/05-bali.jpg
rename to site/web/assets/images/docs/cookbook/effects/parallax/05-bali.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/parallax/06-mexico-city.jpg b/site/web/assets/images/docs/cookbook/effects/parallax/06-mexico-city.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/parallax/06-mexico-city.jpg
rename to site/web/assets/images/docs/cookbook/effects/parallax/06-mexico-city.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/parallax/07-cairo.jpg b/site/web/assets/images/docs/cookbook/effects/parallax/07-cairo.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/parallax/07-cairo.jpg
rename to site/web/assets/images/docs/cookbook/effects/parallax/07-cairo.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/split-check/Avatar1.jpg b/site/web/assets/images/docs/cookbook/effects/split-check/Avatar1.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/split-check/Avatar1.jpg
rename to site/web/assets/images/docs/cookbook/effects/split-check/Avatar1.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/split-check/Avatar2.jpg b/site/web/assets/images/docs/cookbook/effects/split-check/Avatar2.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/split-check/Avatar2.jpg
rename to site/web/assets/images/docs/cookbook/effects/split-check/Avatar2.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/split-check/Avatar3.jpg b/site/web/assets/images/docs/cookbook/effects/split-check/Avatar3.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/split-check/Avatar3.jpg
rename to site/web/assets/images/docs/cookbook/effects/split-check/Avatar3.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/split-check/Food1.jpg b/site/web/assets/images/docs/cookbook/effects/split-check/Food1.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/split-check/Food1.jpg
rename to site/web/assets/images/docs/cookbook/effects/split-check/Food1.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/split-check/Food2.jpg b/site/web/assets/images/docs/cookbook/effects/split-check/Food2.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/split-check/Food2.jpg
rename to site/web/assets/images/docs/cookbook/effects/split-check/Food2.jpg
diff --git a/src/content/assets/images/docs/cookbook/effects/split-check/Food3.jpg b/site/web/assets/images/docs/cookbook/effects/split-check/Food3.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/effects/split-check/Food3.jpg
rename to site/web/assets/images/docs/cookbook/effects/split-check/Food3.jpg
diff --git a/src/content/assets/images/docs/cookbook/fade-in-out.webp b/site/web/assets/images/docs/cookbook/fade-in-out.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/fade-in-out.webp
rename to site/web/assets/images/docs/cookbook/fade-in-out.webp
diff --git a/src/content/assets/images/docs/cookbook/fading-in-asset-demo.webp b/site/web/assets/images/docs/cookbook/fading-in-asset-demo.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/fading-in-asset-demo.webp
rename to site/web/assets/images/docs/cookbook/fading-in-asset-demo.webp
diff --git a/src/content/assets/images/docs/cookbook/fading-in-images.webp b/site/web/assets/images/docs/cookbook/fading-in-images.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/fading-in-images.webp
rename to site/web/assets/images/docs/cookbook/fading-in-images.webp
diff --git a/src/content/assets/images/docs/cookbook/floating-app-bar.webp b/site/web/assets/images/docs/cookbook/floating-app-bar.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/floating-app-bar.webp
rename to site/web/assets/images/docs/cookbook/floating-app-bar.webp
diff --git a/src/content/assets/images/docs/cookbook/focus.webp b/site/web/assets/images/docs/cookbook/focus.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/focus.webp
rename to site/web/assets/images/docs/cookbook/focus.webp
diff --git a/src/content/assets/images/docs/cookbook/fonts.png b/site/web/assets/images/docs/cookbook/fonts.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/fonts.png
rename to site/web/assets/images/docs/cookbook/fonts.png
diff --git a/src/content/assets/images/docs/cookbook/form-validation.webp b/site/web/assets/images/docs/cookbook/form-validation.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/form-validation.webp
rename to site/web/assets/images/docs/cookbook/form-validation.webp
diff --git a/src/content/assets/images/docs/cookbook/google-play-create-app.png b/site/web/assets/images/docs/cookbook/google-play-create-app.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/google-play-create-app.png
rename to site/web/assets/images/docs/cookbook/google-play-create-app.png
diff --git a/src/content/assets/images/docs/cookbook/grid-list.webp b/site/web/assets/images/docs/cookbook/grid-list.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/grid-list.webp
rename to site/web/assets/images/docs/cookbook/grid-list.webp
diff --git a/src/content/assets/images/docs/cookbook/handling-taps.webp b/site/web/assets/images/docs/cookbook/handling-taps.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/handling-taps.webp
rename to site/web/assets/images/docs/cookbook/handling-taps.webp
diff --git a/src/content/assets/images/docs/cookbook/hero.webp b/site/web/assets/images/docs/cookbook/hero.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/hero.webp
rename to site/web/assets/images/docs/cookbook/hero.webp
diff --git a/src/content/assets/images/docs/cookbook/horizontal-list.webp b/site/web/assets/images/docs/cookbook/horizontal-list.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/horizontal-list.webp
rename to site/web/assets/images/docs/cookbook/horizontal-list.webp
diff --git a/src/content/assets/images/docs/cookbook/isolate.webp b/site/web/assets/images/docs/cookbook/isolate.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/isolate.webp
rename to site/web/assets/images/docs/cookbook/isolate.webp
diff --git a/src/content/assets/images/docs/cookbook/long-lists.webp b/site/web/assets/images/docs/cookbook/long-lists.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/long-lists.webp
rename to site/web/assets/images/docs/cookbook/long-lists.webp
diff --git a/src/content/assets/images/docs/cookbook/mixed-list.png b/site/web/assets/images/docs/cookbook/mixed-list.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/mixed-list.png
rename to site/web/assets/images/docs/cookbook/mixed-list.png
diff --git a/src/content/assets/images/docs/cookbook/multiplayer-areas.jpg b/site/web/assets/images/docs/cookbook/multiplayer-areas.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/multiplayer-areas.jpg
rename to site/web/assets/images/docs/cookbook/multiplayer-areas.jpg
diff --git a/src/content/assets/images/docs/cookbook/multiplayer-card-game.jpg b/site/web/assets/images/docs/cookbook/multiplayer-card-game.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/multiplayer-card-game.jpg
rename to site/web/assets/images/docs/cookbook/multiplayer-card-game.jpg
diff --git a/src/content/assets/images/docs/cookbook/multiplayer-firebase-data.png b/site/web/assets/images/docs/cookbook/multiplayer-firebase-data.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/multiplayer-firebase-data.png
rename to site/web/assets/images/docs/cookbook/multiplayer-firebase-data.png
diff --git a/src/content/assets/images/docs/cookbook/multiplayer-firebase-match.png b/site/web/assets/images/docs/cookbook/multiplayer-firebase-match.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/multiplayer-firebase-match.png
rename to site/web/assets/images/docs/cookbook/multiplayer-firebase-match.png
diff --git a/src/content/assets/images/docs/cookbook/multiplayer-two-mobiles.jpg b/site/web/assets/images/docs/cookbook/multiplayer-two-mobiles.jpg
similarity index 100%
rename from src/content/assets/images/docs/cookbook/multiplayer-two-mobiles.jpg
rename to site/web/assets/images/docs/cookbook/multiplayer-two-mobiles.jpg
diff --git a/src/content/assets/images/docs/cookbook/navigate-with-arguments.webp b/site/web/assets/images/docs/cookbook/navigate-with-arguments.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/navigate-with-arguments.webp
rename to site/web/assets/images/docs/cookbook/navigate-with-arguments.webp
diff --git a/src/content/assets/images/docs/cookbook/navigation-basics-cupertino.webp b/site/web/assets/images/docs/cookbook/navigation-basics-cupertino.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/navigation-basics-cupertino.webp
rename to site/web/assets/images/docs/cookbook/navigation-basics-cupertino.webp
diff --git a/src/content/assets/images/docs/cookbook/navigation-basics.webp b/site/web/assets/images/docs/cookbook/navigation-basics.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/navigation-basics.webp
rename to site/web/assets/images/docs/cookbook/navigation-basics.webp
diff --git a/src/content/assets/images/docs/cookbook/network-image.png b/site/web/assets/images/docs/cookbook/network-image.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/network-image.png
rename to site/web/assets/images/docs/cookbook/network-image.png
diff --git a/src/content/assets/images/docs/cookbook/orientation.webp b/site/web/assets/images/docs/cookbook/orientation.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/orientation.webp
rename to site/web/assets/images/docs/cookbook/orientation.webp
diff --git a/src/content/assets/images/docs/cookbook/package-fonts.png b/site/web/assets/images/docs/cookbook/package-fonts.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/package-fonts.png
rename to site/web/assets/images/docs/cookbook/package-fonts.png
diff --git a/src/content/assets/images/docs/cookbook/page-route-animation.webp b/site/web/assets/images/docs/cookbook/page-route-animation.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/page-route-animation.webp
rename to site/web/assets/images/docs/cookbook/page-route-animation.webp
diff --git a/src/content/assets/images/docs/cookbook/passing-data.webp b/site/web/assets/images/docs/cookbook/passing-data.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/passing-data.webp
rename to site/web/assets/images/docs/cookbook/passing-data.webp
diff --git a/src/content/assets/images/docs/cookbook/play-console-play-games-services.png b/site/web/assets/images/docs/cookbook/play-console-play-games-services.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/play-console-play-games-services.png
rename to site/web/assets/images/docs/cookbook/play-console-play-games-services.png
diff --git a/src/content/assets/images/docs/cookbook/retrieve-input.webp b/site/web/assets/images/docs/cookbook/retrieve-input.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/retrieve-input.webp
rename to site/web/assets/images/docs/cookbook/retrieve-input.webp
diff --git a/src/content/assets/images/docs/cookbook/returning-data.webp b/site/web/assets/images/docs/cookbook/returning-data.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/returning-data.webp
rename to site/web/assets/images/docs/cookbook/returning-data.webp
diff --git a/src/content/assets/images/docs/cookbook/ripples.webp b/site/web/assets/images/docs/cookbook/ripples.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/ripples.webp
rename to site/web/assets/images/docs/cookbook/ripples.webp
diff --git a/src/content/assets/images/docs/cookbook/set-up-app-links-emulator-deeplinked.png b/site/web/assets/images/docs/cookbook/set-up-app-links-emulator-deeplinked.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/set-up-app-links-emulator-deeplinked.png
rename to site/web/assets/images/docs/cookbook/set-up-app-links-emulator-deeplinked.png
diff --git a/src/content/assets/images/docs/cookbook/set-up-app-links-emulator-installed.png b/site/web/assets/images/docs/cookbook/set-up-app-links-emulator-installed.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/set-up-app-links-emulator-installed.png
rename to site/web/assets/images/docs/cookbook/set-up-app-links-emulator-installed.png
diff --git a/src/content/assets/images/docs/cookbook/set-up-app-links-pdc-signing-key.png b/site/web/assets/images/docs/cookbook/set-up-app-links-pdc-signing-key.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/set-up-app-links-pdc-signing-key.png
rename to site/web/assets/images/docs/cookbook/set-up-app-links-pdc-signing-key.png
diff --git a/src/content/assets/images/docs/cookbook/set-up-universal-links-add-associated-domains.png b/site/web/assets/images/docs/cookbook/set-up-universal-links-add-associated-domains.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/set-up-universal-links-add-associated-domains.png
rename to site/web/assets/images/docs/cookbook/set-up-universal-links-add-associated-domains.png
diff --git a/src/content/assets/images/docs/cookbook/set-up-universal-links-associated-domains.png b/site/web/assets/images/docs/cookbook/set-up-universal-links-associated-domains.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/set-up-universal-links-associated-domains.png
rename to site/web/assets/images/docs/cookbook/set-up-universal-links-associated-domains.png
diff --git a/src/content/assets/images/docs/cookbook/set-up-universal-links-simulator-deeplinked.png b/site/web/assets/images/docs/cookbook/set-up-universal-links-simulator-deeplinked.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/set-up-universal-links-simulator-deeplinked.png
rename to site/web/assets/images/docs/cookbook/set-up-universal-links-simulator-deeplinked.png
diff --git a/src/content/assets/images/docs/cookbook/set-up-universal-links-simulator.png b/site/web/assets/images/docs/cookbook/set-up-universal-links-simulator.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/set-up-universal-links-simulator.png
rename to site/web/assets/images/docs/cookbook/set-up-universal-links-simulator.png
diff --git a/src/content/assets/images/docs/cookbook/snackbar.webp b/site/web/assets/images/docs/cookbook/snackbar.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/snackbar.webp
rename to site/web/assets/images/docs/cookbook/snackbar.webp
diff --git a/src/content/assets/images/docs/cookbook/spaced-items-1.png b/site/web/assets/images/docs/cookbook/spaced-items-1.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/spaced-items-1.png
rename to site/web/assets/images/docs/cookbook/spaced-items-1.png
diff --git a/src/content/assets/images/docs/cookbook/spaced-items-2.png b/site/web/assets/images/docs/cookbook/spaced-items-2.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/spaced-items-2.png
rename to site/web/assets/images/docs/cookbook/spaced-items-2.png
diff --git a/src/content/assets/images/docs/cookbook/tabs.webp b/site/web/assets/images/docs/cookbook/tabs.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/tabs.webp
rename to site/web/assets/images/docs/cookbook/tabs.webp
diff --git a/src/content/assets/images/docs/cookbook/themes.png b/site/web/assets/images/docs/cookbook/themes.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/themes.png
rename to site/web/assets/images/docs/cookbook/themes.png
diff --git a/src/content/assets/images/docs/cookbook/types-of-gamer-motivations.png b/site/web/assets/images/docs/cookbook/types-of-gamer-motivations.png
similarity index 100%
rename from src/content/assets/images/docs/cookbook/types-of-gamer-motivations.png
rename to site/web/assets/images/docs/cookbook/types-of-gamer-motivations.png
diff --git a/src/content/assets/images/docs/cookbook/web-sockets.webp b/site/web/assets/images/docs/cookbook/web-sockets.webp
similarity index 100%
rename from src/content/assets/images/docs/cookbook/web-sockets.webp
rename to site/web/assets/images/docs/cookbook/web-sockets.webp
diff --git a/src/content/assets/images/docs/crash_reports.png b/site/web/assets/images/docs/crash_reports.png
similarity index 100%
rename from src/content/assets/images/docs/crash_reports.png
rename to site/web/assets/images/docs/crash_reports.png
diff --git a/src/content/assets/images/docs/declarativeUIchanges.png b/site/web/assets/images/docs/declarativeUIchanges.png
similarity index 100%
rename from src/content/assets/images/docs/declarativeUIchanges.png
rename to site/web/assets/images/docs/declarativeUIchanges.png
diff --git a/src/content/assets/images/docs/deployment/android/build-variant-menu.png b/site/web/assets/images/docs/deployment/android/build-variant-menu.png
similarity index 100%
rename from src/content/assets/images/docs/deployment/android/build-variant-menu.png
rename to site/web/assets/images/docs/deployment/android/build-variant-menu.png
diff --git a/src/content/assets/images/docs/deployment/android/cli-multidex-added-build.png b/site/web/assets/images/docs/deployment/android/cli-multidex-added-build.png
similarity index 100%
rename from src/content/assets/images/docs/deployment/android/cli-multidex-added-build.png
rename to site/web/assets/images/docs/deployment/android/cli-multidex-added-build.png
diff --git a/src/content/assets/images/docs/deployment/android/cli-select-device.png b/site/web/assets/images/docs/deployment/android/cli-select-device.png
similarity index 100%
rename from src/content/assets/images/docs/deployment/android/cli-select-device.png
rename to site/web/assets/images/docs/deployment/android/cli-select-device.png
diff --git a/src/content/assets/images/docs/deployment/android/gradle-script-menu.png b/site/web/assets/images/docs/deployment/android/gradle-script-menu.png
similarity index 100%
rename from src/content/assets/images/docs/deployment/android/gradle-script-menu.png
rename to site/web/assets/images/docs/deployment/android/gradle-script-menu.png
diff --git a/src/content/assets/images/docs/deployment/android/ide-build-failure-multidex.png b/site/web/assets/images/docs/deployment/android/ide-build-failure-multidex.png
similarity index 100%
rename from src/content/assets/images/docs/deployment/android/ide-build-failure-multidex.png
rename to site/web/assets/images/docs/deployment/android/ide-build-failure-multidex.png
diff --git a/src/content/assets/images/docs/development/add-to-app/android-overview.webp b/site/web/assets/images/docs/development/add-to-app/android-overview.webp
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android-overview.webp
rename to site/web/assets/images/docs/development/add-to-app/android-overview.webp
diff --git a/src/content/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_fullscreen.png b/site/web/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_fullscreen.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_fullscreen.png
rename to site/web/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_fullscreen.png
diff --git a/src/content/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_header.png b/site/web/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_header.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_header.png
rename to site/web/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_header.png
diff --git a/src/content/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_partial-ui.png b/site/web/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_partial-ui.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_partial-ui.png
rename to site/web/assets/images/docs/development/add-to-app/android/add-flutter-fragment/add-flutter-fragment_partial-ui.png
diff --git a/src/content/assets/images/docs/development/add-to-app/android/add-flutter-screen/add-single-flutter-screen-transparent_header.png b/site/web/assets/images/docs/development/add-to-app/android/add-flutter-screen/add-single-flutter-screen-transparent_header.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/add-flutter-screen/add-single-flutter-screen-transparent_header.png
rename to site/web/assets/images/docs/development/add-to-app/android/add-flutter-screen/add-single-flutter-screen-transparent_header.png
diff --git a/src/content/assets/images/docs/development/add-to-app/android/add-flutter-screen/add-single-flutter-screen_header.png b/site/web/assets/images/docs/development/add-to-app/android/add-flutter-screen/add-single-flutter-screen_header.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/add-flutter-screen/add-single-flutter-screen_header.png
rename to site/web/assets/images/docs/development/add-to-app/android/add-flutter-screen/add-single-flutter-screen_header.png
diff --git a/src/content/assets/images/docs/development/add-to-app/android/add-flutter-view/add-view-sample.webp b/site/web/assets/images/docs/development/add-to-app/android/add-flutter-view/add-view-sample.webp
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/add-flutter-view/add-view-sample.webp
rename to site/web/assets/images/docs/development/add-to-app/android/add-flutter-view/add-view-sample.webp
diff --git a/src/content/assets/images/docs/development/add-to-app/android/project-setup/build-aar-instructions.png b/site/web/assets/images/docs/development/add-to-app/android/project-setup/build-aar-instructions.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/project-setup/build-aar-instructions.png
rename to site/web/assets/images/docs/development/add-to-app/android/project-setup/build-aar-instructions.png
diff --git a/src/content/assets/images/docs/development/add-to-app/android/project-setup/ide-build-aar.png b/site/web/assets/images/docs/development/add-to-app/android/project-setup/ide-build-aar.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/project-setup/ide-build-aar.png
rename to site/web/assets/images/docs/development/add-to-app/android/project-setup/ide-build-aar.png
diff --git a/src/content/assets/images/docs/development/add-to-app/android/project-setup/ide-new-module.png b/site/web/assets/images/docs/development/add-to-app/android/project-setup/ide-new-module.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/android/project-setup/ide-new-module.png
rename to site/web/assets/images/docs/development/add-to-app/android/project-setup/ide-new-module.png
diff --git a/src/content/assets/images/docs/development/add-to-app/debugging/wireless-port.png b/site/web/assets/images/docs/development/add-to-app/debugging/wireless-port.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/debugging/wireless-port.png
rename to site/web/assets/images/docs/development/add-to-app/debugging/wireless-port.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios-overview.webp b/site/web/assets/images/docs/development/add-to-app/ios-overview.webp
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios-overview.webp
rename to site/web/assets/images/docs/development/add-to-app/ios-overview.webp
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/choose-libraries.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/choose-libraries.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/choose-libraries.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/choose-libraries.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/choose-to-embed.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/choose-to-embed.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/choose-to-embed.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/choose-to-embed.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/copy-bundle.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/copy-bundle.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/copy-bundle.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/copy-bundle.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/debug-plist.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/debug-plist.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/debug-plist.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/debug-plist.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/embed-xcode.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/embed-xcode.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/embed-xcode.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/embed-xcode.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/excluded-archs.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/excluded-archs.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/excluded-archs.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/excluded-archs.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/framework-search-paths.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/framework-search-paths.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/framework-search-paths.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/framework-search-paths.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/linked-libraries.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/linked-libraries.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/linked-libraries.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/linked-libraries.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/network-permission.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/network-permission.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/network-permission.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/network-permission.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/plist-build-setting.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/plist-build-setting.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/plist-build-setting.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/plist-build-setting.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/project-pbxproj.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/project-pbxproj.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/project-pbxproj.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/project-pbxproj.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ios/project-setup/set-plist-build-setting.png b/site/web/assets/images/docs/development/add-to-app/ios/project-setup/set-plist-build-setting.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ios/project-setup/set-plist-build-setting.png
rename to site/web/assets/images/docs/development/add-to-app/ios/project-setup/set-plist-build-setting.png
diff --git a/src/content/assets/images/docs/development/add-to-app/ipv6.png b/site/web/assets/images/docs/development/add-to-app/ipv6.png
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/ipv6.png
rename to site/web/assets/images/docs/development/add-to-app/ipv6.png
diff --git a/src/content/assets/images/docs/development/add-to-app/multiple-flutters-sample.webp b/site/web/assets/images/docs/development/add-to-app/multiple-flutters-sample.webp
similarity index 100%
rename from src/content/assets/images/docs/development/add-to-app/multiple-flutters-sample.webp
rename to site/web/assets/images/docs/development/add-to-app/multiple-flutters-sample.webp
diff --git a/src/content/assets/images/docs/development/concurrency/basics-main-isolate.png b/site/web/assets/images/docs/development/concurrency/basics-main-isolate.png
similarity index 100%
rename from src/content/assets/images/docs/development/concurrency/basics-main-isolate.png
rename to site/web/assets/images/docs/development/concurrency/basics-main-isolate.png
diff --git a/src/content/assets/images/docs/development/concurrency/event-jank.png b/site/web/assets/images/docs/development/concurrency/event-jank.png
similarity index 100%
rename from src/content/assets/images/docs/development/concurrency/event-jank.png
rename to site/web/assets/images/docs/development/concurrency/event-jank.png
diff --git a/src/content/assets/images/docs/development/concurrency/isolate-bg-worker.png b/site/web/assets/images/docs/development/concurrency/isolate-bg-worker.png
similarity index 100%
rename from src/content/assets/images/docs/development/concurrency/isolate-bg-worker.png
rename to site/web/assets/images/docs/development/concurrency/isolate-bg-worker.png
diff --git a/src/content/assets/images/docs/development/data-and-backend/state-mgmt/ephemeral-vs-app-state.png b/site/web/assets/images/docs/development/data-and-backend/state-mgmt/ephemeral-vs-app-state.png
similarity index 100%
rename from src/content/assets/images/docs/development/data-and-backend/state-mgmt/ephemeral-vs-app-state.png
rename to site/web/assets/images/docs/development/data-and-backend/state-mgmt/ephemeral-vs-app-state.png
diff --git a/src/content/assets/images/docs/development/data-and-backend/state-mgmt/model-shopper-screencast.webp b/site/web/assets/images/docs/development/data-and-backend/state-mgmt/model-shopper-screencast.webp
similarity index 100%
rename from src/content/assets/images/docs/development/data-and-backend/state-mgmt/model-shopper-screencast.webp
rename to site/web/assets/images/docs/development/data-and-backend/state-mgmt/model-shopper-screencast.webp
diff --git a/src/content/assets/images/docs/development/data-and-backend/state-mgmt/simple-widget-tree-with-cart.png b/site/web/assets/images/docs/development/data-and-backend/state-mgmt/simple-widget-tree-with-cart.png
similarity index 100%
rename from src/content/assets/images/docs/development/data-and-backend/state-mgmt/simple-widget-tree-with-cart.png
rename to site/web/assets/images/docs/development/data-and-backend/state-mgmt/simple-widget-tree-with-cart.png
diff --git a/src/content/assets/images/docs/development/data-and-backend/state-mgmt/simple-widget-tree.png b/site/web/assets/images/docs/development/data-and-backend/state-mgmt/simple-widget-tree.png
similarity index 100%
rename from src/content/assets/images/docs/development/data-and-backend/state-mgmt/simple-widget-tree.png
rename to site/web/assets/images/docs/development/data-and-backend/state-mgmt/simple-widget-tree.png
diff --git a/src/content/assets/images/docs/development/data-and-backend/state-mgmt/state-management-explainer.webp b/site/web/assets/images/docs/development/data-and-backend/state-mgmt/state-management-explainer.webp
similarity index 100%
rename from src/content/assets/images/docs/development/data-and-backend/state-mgmt/state-management-explainer.webp
rename to site/web/assets/images/docs/development/data-and-backend/state-mgmt/state-management-explainer.webp
diff --git a/src/content/assets/images/docs/development/data-and-backend/state-mgmt/ui-equals-function-of-state.png b/site/web/assets/images/docs/development/data-and-backend/state-mgmt/ui-equals-function-of-state.png
similarity index 100%
rename from src/content/assets/images/docs/development/data-and-backend/state-mgmt/ui-equals-function-of-state.png
rename to site/web/assets/images/docs/development/data-and-backend/state-mgmt/ui-equals-function-of-state.png
diff --git a/src/content/assets/images/docs/development/device-connect.png b/site/web/assets/images/docs/development/device-connect.png
similarity index 100%
rename from src/content/assets/images/docs/development/device-connect.png
rename to site/web/assets/images/docs/development/device-connect.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/FlutterFavoriteLogo.png b/site/web/assets/images/docs/development/packages-and-plugins/FlutterFavoriteLogo.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/FlutterFavoriteLogo.png
rename to site/web/assets/images/docs/development/packages-and-plugins/FlutterFavoriteLogo.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-flutter-pre-action.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-flutter-pre-action.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-flutter-pre-action.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-flutter-pre-action.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-generated-framework.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-generated-framework.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-generated-framework.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-generated-framework.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-runner-tests-link-binary-with-libraries.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-runner-tests-link-binary-with-libraries.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-runner-tests-link-binary-with-libraries.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/add-runner-tests-link-binary-with-libraries.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/choose-package-products-test.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/choose-package-products-test.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/choose-package-products-test.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/choose-package-products-test.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/choose-package-products.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/choose-package-products.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/choose-package-products.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/choose-package-products.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/flutter-pre-action-build-log.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/flutter-pre-action-build-log.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/flutter-pre-action-build-log.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/flutter-pre-action-build-log.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/minimum-deployments.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/minimum-deployments.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/minimum-deployments.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/minimum-deployments.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/package-dependencies.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/package-dependencies.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/package-dependencies.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/package-dependencies.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-flutter-pre-action.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-flutter-pre-action.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-flutter-pre-action.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-flutter-pre-action.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-generated-framework.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-generated-framework.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-generated-framework.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-generated-framework.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-generated-package.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-generated-package.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-generated-package.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/remove-generated-package.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/runner-tests-link-binary-with-libraries.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/runner-tests-link-binary-with-libraries.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/runner-tests-link-binary-with-libraries.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/runner-tests-link-binary-with-libraries.png
diff --git a/src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/search-for-ocmock.png b/site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/search-for-ocmock.png
similarity index 100%
rename from src/content/assets/images/docs/development/packages-and-plugins/swift-package-manager/search-for-ocmock.png
rename to site/web/assets/images/docs/development/packages-and-plugins/swift-package-manager/search-for-ocmock.png
diff --git a/src/content/assets/images/docs/development/platform-integration/app-extensions/share-extension-open-app.gif b/site/web/assets/images/docs/development/platform-integration/app-extensions/share-extension-open-app.gif
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/app-extensions/share-extension-open-app.gif
rename to site/web/assets/images/docs/development/platform-integration/app-extensions/share-extension-open-app.gif
diff --git a/src/content/assets/images/docs/development/platform-integration/app-extensions/share-extension.png b/site/web/assets/images/docs/development/platform-integration/app-extensions/share-extension.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/app-extensions/share-extension.png
rename to site/web/assets/images/docs/development/platform-integration/app-extensions/share-extension.png
diff --git a/src/content/assets/images/docs/development/platform-integration/app-extensions/xcode-app-groups.png b/site/web/assets/images/docs/development/platform-integration/app-extensions/xcode-app-groups.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/app-extensions/xcode-app-groups.png
rename to site/web/assets/images/docs/development/platform-integration/app-extensions/xcode-app-groups.png
diff --git a/src/content/assets/images/docs/development/platform-integration/app-extensions/xcode-configurations.png b/site/web/assets/images/docs/development/platform-integration/app-extensions/xcode-configurations.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/app-extensions/xcode-configurations.png
rename to site/web/assets/images/docs/development/platform-integration/app-extensions/xcode-configurations.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/activate-scheme.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/activate-scheme.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/activate-scheme.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/activate-scheme.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/add-app-clip.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/add-app-clip.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/add-app-clip.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/add-app-clip.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/add-target-membership.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/add-target-membership.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/add-target-membership.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/add-target-membership.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/add-target.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/add-target.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/add-target.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/add-target.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/app-clip-details.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/app-clip-details.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/app-clip-details.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/app-clip-details.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/app-clip-entitlements.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/app-clip-entitlements.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/app-clip-entitlements.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/app-clip-entitlements.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/bridge-header.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/bridge-header.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/bridge-header.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/bridge-header.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/clean-files.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/clean-files.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/clean-files.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/clean-files.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/configuration.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/configuration.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/configuration.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/configuration.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/embedded-app-clips.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/embedded-app-clips.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/embedded-app-clips.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/embedded-app-clips.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/main-app-entitlements-setting.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/main-app-entitlements-setting.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/main-app-entitlements-setting.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/main-app-entitlements-setting.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/main-app-entitlements.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/main-app-entitlements.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/main-app-entitlements.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/main-app-entitlements.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/new-build-phase.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/new-build-phase.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/new-build-phase.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/new-build-phase.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/observatory-uri.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/observatory-uri.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/observatory-uri.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/observatory-uri.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/run-select.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/run-select.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/run-select.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/run-select.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/scene-manifest.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/scene-manifest.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/scene-manifest.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/scene-manifest.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/xcode-backend-build.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/xcode-backend-build.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/xcode-backend-build.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/xcode-backend-build.png
diff --git a/src/content/assets/images/docs/development/platform-integration/ios-app-clip/xcode-backend-embed.png b/site/web/assets/images/docs/development/platform-integration/ios-app-clip/xcode-backend-embed.png
similarity index 100%
rename from src/content/assets/images/docs/development/platform-integration/ios-app-clip/xcode-backend-embed.png
rename to site/web/assets/images/docs/development/platform-integration/ios-app-clip/xcode-backend-embed.png
diff --git a/src/content/assets/images/docs/development/tools/android-studio-run-controls.png b/site/web/assets/images/docs/development/tools/android-studio-run-controls.png
similarity index 100%
rename from src/content/assets/images/docs/development/tools/android-studio-run-controls.png
rename to site/web/assets/images/docs/development/tools/android-studio-run-controls.png
diff --git a/src/content/assets/images/docs/development/tools/flutter-fix-suggestion-intellij.png b/site/web/assets/images/docs/development/tools/flutter-fix-suggestion-intellij.png
similarity index 100%
rename from src/content/assets/images/docs/development/tools/flutter-fix-suggestion-intellij.png
rename to site/web/assets/images/docs/development/tools/flutter-fix-suggestion-intellij.png
diff --git a/src/content/assets/images/docs/development/tools/flutter-fix-suggestion-vscode.png b/site/web/assets/images/docs/development/tools/flutter-fix-suggestion-vscode.png
similarity index 100%
rename from src/content/assets/images/docs/development/tools/flutter-fix-suggestion-vscode.png
rename to site/web/assets/images/docs/development/tools/flutter-fix-suggestion-vscode.png
diff --git a/src/content/assets/images/docs/development/ui/splash-screen/android-splash-screen/splash-screens_header.png b/site/web/assets/images/docs/development/ui/splash-screen/android-splash-screen/splash-screens_header.png
similarity index 100%
rename from src/content/assets/images/docs/development/ui/splash-screen/android-splash-screen/splash-screens_header.png
rename to site/web/assets/images/docs/development/ui/splash-screen/android-splash-screen/splash-screens_header.png
diff --git a/src/content/assets/images/docs/development/ui/typography/feature-tag-example.png b/site/web/assets/images/docs/development/ui/typography/feature-tag-example.png
similarity index 100%
rename from src/content/assets/images/docs/development/ui/typography/feature-tag-example.png
rename to site/web/assets/images/docs/development/ui/typography/feature-tag-example.png
diff --git a/src/content/assets/images/docs/development/ui/typography/google-fonts-type-tester.png b/site/web/assets/images/docs/development/ui/typography/google-fonts-type-tester.png
similarity index 100%
rename from src/content/assets/images/docs/development/ui/typography/google-fonts-type-tester.png
rename to site/web/assets/images/docs/development/ui/typography/google-fonts-type-tester.png
diff --git a/src/content/assets/images/docs/development/ui/typography/google-fonts-type-tester.webp b/site/web/assets/images/docs/development/ui/typography/google-fonts-type-tester.webp
similarity index 100%
rename from src/content/assets/images/docs/development/ui/typography/google-fonts-type-tester.webp
rename to site/web/assets/images/docs/development/ui/typography/google-fonts-type-tester.webp
diff --git a/src/content/assets/images/docs/development/ui/typography/roboto-serif-font-axes.png b/site/web/assets/images/docs/development/ui/typography/roboto-serif-font-axes.png
similarity index 100%
rename from src/content/assets/images/docs/development/ui/typography/roboto-serif-font-axes.png
rename to site/web/assets/images/docs/development/ui/typography/roboto-serif-font-axes.png
diff --git a/src/content/assets/images/docs/development/ui/typography/typographical-scale.png b/site/web/assets/images/docs/development/ui/typography/typographical-scale.png
similarity index 100%
rename from src/content/assets/images/docs/development/ui/typography/typographical-scale.png
rename to site/web/assets/images/docs/development/ui/typography/typographical-scale.png
diff --git a/src/content/assets/images/docs/development/ui/typography/variable-font-axes.png b/site/web/assets/images/docs/development/ui/typography/variable-font-axes.png
similarity index 100%
rename from src/content/assets/images/docs/development/ui/typography/variable-font-axes.png
rename to site/web/assets/images/docs/development/ui/typography/variable-font-axes.png
diff --git a/src/content/assets/images/docs/favicon.png b/site/web/assets/images/docs/favicon.png
similarity index 100%
rename from src/content/assets/images/docs/favicon.png
rename to site/web/assets/images/docs/favicon.png
diff --git a/src/content/assets/images/docs/flavors/flavors-android-app-names-1.png b/site/web/assets/images/docs/flavors/flavors-android-app-names-1.png
similarity index 100%
rename from src/content/assets/images/docs/flavors/flavors-android-app-names-1.png
rename to site/web/assets/images/docs/flavors/flavors-android-app-names-1.png
diff --git a/src/content/assets/images/docs/flavors/flavors-android-icons.png b/site/web/assets/images/docs/flavors/flavors-android-icons.png
similarity index 100%
rename from src/content/assets/images/docs/flavors/flavors-android-icons.png
rename to site/web/assets/images/docs/flavors/flavors-android-icons.png
diff --git a/src/content/assets/images/docs/flavors/flavors-ios-app-names.png b/site/web/assets/images/docs/flavors/flavors-ios-app-names.png
similarity index 100%
rename from src/content/assets/images/docs/flavors/flavors-ios-app-names.png
rename to site/web/assets/images/docs/flavors/flavors-ios-app-names.png
diff --git a/src/content/assets/images/docs/flavors/flavors-ios-icons.png b/site/web/assets/images/docs/flavors/flavors-ios-icons.png
similarity index 100%
rename from src/content/assets/images/docs/flavors/flavors-ios-icons.png
rename to site/web/assets/images/docs/flavors/flavors-ios-icons.png
diff --git a/src/content/assets/images/docs/flavors/flavors-ios-scheme-configurations.png b/site/web/assets/images/docs/flavors/flavors-ios-scheme-configurations.png
similarity index 100%
rename from src/content/assets/images/docs/flavors/flavors-ios-scheme-configurations.png
rename to site/web/assets/images/docs/flavors/flavors-ios-scheme-configurations.png
diff --git a/src/content/assets/images/docs/flavors/flavors-ios-schemes.png b/site/web/assets/images/docs/flavors/flavors-ios-schemes.png
similarity index 100%
rename from src/content/assets/images/docs/flavors/flavors-ios-schemes.png
rename to site/web/assets/images/docs/flavors/flavors-ios-schemes.png
diff --git a/src/content/assets/images/docs/flavors/flavors-ios-test-scheme.png b/site/web/assets/images/docs/flavors/flavors-ios-test-scheme.png
similarity index 100%
rename from src/content/assets/images/docs/flavors/flavors-ios-test-scheme.png
rename to site/web/assets/images/docs/flavors/flavors-ios-test-scheme.png
diff --git a/src/content/assets/images/docs/flutter-mono-81x100.png b/site/web/assets/images/docs/flutter-mono-81x100.png
similarity index 100%
rename from src/content/assets/images/docs/flutter-mono-81x100.png
rename to site/web/assets/images/docs/flutter-mono-81x100.png
diff --git a/src/content/assets/images/docs/fwe/dash-search.png b/site/web/assets/images/docs/fwe/dash-search.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/dash-search.png
rename to site/web/assets/images/docs/fwe/dash-search.png
diff --git a/src/content/assets/images/docs/fwe/layout/alternating_list_items.png b/site/web/assets/images/docs/fwe/layout/alternating_list_items.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/alternating_list_items.png
rename to site/web/assets/images/docs/fwe/layout/alternating_list_items.png
diff --git a/src/content/assets/images/docs/fwe/layout/axes_diagram.png b/site/web/assets/images/docs/fwe/layout/axes_diagram.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/axes_diagram.png
rename to site/web/assets/images/docs/fwe/layout/axes_diagram.png
diff --git a/src/content/assets/images/docs/fwe/layout/basic_listview.png b/site/web/assets/images/docs/fwe/layout/basic_listview.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/basic_listview.png
rename to site/web/assets/images/docs/fwe/layout/basic_listview.png
diff --git a/src/content/assets/images/docs/fwe/layout/center.png b/site/web/assets/images/docs/fwe/layout/center.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/center.png
rename to site/web/assets/images/docs/fwe/layout/center.png
diff --git a/src/content/assets/images/docs/fwe/layout/col_space_evenly.png b/site/web/assets/images/docs/fwe/layout/col_space_evenly.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/col_space_evenly.png
rename to site/web/assets/images/docs/fwe/layout/col_space_evenly.png
diff --git a/src/content/assets/images/docs/fwe/layout/expanded_row.png b/site/web/assets/images/docs/fwe/layout/expanded_row.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/expanded_row.png
rename to site/web/assets/images/docs/fwe/layout/expanded_row.png
diff --git a/src/content/assets/images/docs/fwe/layout/flex_2_row.png b/site/web/assets/images/docs/fwe/layout/flex_2_row.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/flex_2_row.png
rename to site/web/assets/images/docs/fwe/layout/flex_2_row.png
diff --git a/src/content/assets/images/docs/fwe/layout/layout_builder.png b/site/web/assets/images/docs/fwe/layout/layout_builder.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/layout_builder.png
rename to site/web/assets/images/docs/fwe/layout/layout_builder.png
diff --git a/src/content/assets/images/docs/fwe/layout/left_alignment.png b/site/web/assets/images/docs/fwe/layout/left_alignment.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/left_alignment.png
rename to site/web/assets/images/docs/fwe/layout/left_alignment.png
diff --git a/src/content/assets/images/docs/fwe/layout/listview_builder.png b/site/web/assets/images/docs/fwe/layout/listview_builder.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/listview_builder.png
rename to site/web/assets/images/docs/fwe/layout/listview_builder.png
diff --git a/src/content/assets/images/docs/fwe/layout/nested_row_column.png b/site/web/assets/images/docs/fwe/layout/nested_row_column.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/nested_row_column.png
rename to site/web/assets/images/docs/fwe/layout/nested_row_column.png
diff --git a/src/content/assets/images/docs/fwe/layout/overflowing_row.png b/site/web/assets/images/docs/fwe/layout/overflowing_row.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/overflowing_row.png
rename to site/web/assets/images/docs/fwe/layout/overflowing_row.png
diff --git a/src/content/assets/images/docs/fwe/layout/padding.png b/site/web/assets/images/docs/fwe/layout/padding.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/padding.png
rename to site/web/assets/images/docs/fwe/layout/padding.png
diff --git a/src/content/assets/images/docs/fwe/layout/row.png b/site/web/assets/images/docs/fwe/layout/row.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/row.png
rename to site/web/assets/images/docs/fwe/layout/row.png
diff --git a/src/content/assets/images/docs/fwe/layout/simple_row_column_widget_tree.png b/site/web/assets/images/docs/fwe/layout/simple_row_column_widget_tree.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/simple_row_column_widget_tree.png
rename to site/web/assets/images/docs/fwe/layout/simple_row_column_widget_tree.png
diff --git a/src/content/assets/images/docs/fwe/layout/space_evenly.png b/site/web/assets/images/docs/fwe/layout/space_evenly.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/layout/space_evenly.png
rename to site/web/assets/images/docs/fwe/layout/space_evenly.png
diff --git a/src/content/assets/images/docs/fwe/simple_composition_example.png b/site/web/assets/images/docs/fwe/simple_composition_example.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/simple_composition_example.png
rename to site/web/assets/images/docs/fwe/simple_composition_example.png
diff --git a/src/content/assets/images/docs/fwe/user-input/DatePicker.webp b/site/web/assets/images/docs/fwe/user-input/DatePicker.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/DatePicker.webp
rename to site/web/assets/images/docs/fwe/user-input/DatePicker.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/Dismissible.webp b/site/web/assets/images/docs/fwe/user-input/Dismissible.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/Dismissible.webp
rename to site/web/assets/images/docs/fwe/user-input/Dismissible.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/ElevatedButton.webp b/site/web/assets/images/docs/fwe/user-input/ElevatedButton.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/ElevatedButton.webp
rename to site/web/assets/images/docs/fwe/user-input/ElevatedButton.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/Radio.webp b/site/web/assets/images/docs/fwe/user-input/Radio.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/Radio.webp
rename to site/web/assets/images/docs/fwe/user-input/Radio.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/RichText.png b/site/web/assets/images/docs/fwe/user-input/RichText.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/RichText.png
rename to site/web/assets/images/docs/fwe/user-input/RichText.png
diff --git a/src/content/assets/images/docs/fwe/user-input/RichText_whitebg.png b/site/web/assets/images/docs/fwe/user-input/RichText_whitebg.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/RichText_whitebg.png
rename to site/web/assets/images/docs/fwe/user-input/RichText_whitebg.png
diff --git a/src/content/assets/images/docs/fwe/user-input/SelectableText.webp b/site/web/assets/images/docs/fwe/user-input/SelectableText.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/SelectableText.webp
rename to site/web/assets/images/docs/fwe/user-input/SelectableText.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/SpecialListTiles.webp b/site/web/assets/images/docs/fwe/user-input/SpecialListTiles.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/SpecialListTiles.webp
rename to site/web/assets/images/docs/fwe/user-input/SpecialListTiles.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/Switch.webp b/site/web/assets/images/docs/fwe/user-input/Switch.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/Switch.webp
rename to site/web/assets/images/docs/fwe/user-input/Switch.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/TextField.webp b/site/web/assets/images/docs/fwe/user-input/TextField.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/TextField.webp
rename to site/web/assets/images/docs/fwe/user-input/TextField.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/TimePicker.webp b/site/web/assets/images/docs/fwe/user-input/TimePicker.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/TimePicker.webp
rename to site/web/assets/images/docs/fwe/user-input/TimePicker.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/checkbox.webp b/site/web/assets/images/docs/fwe/user-input/checkbox.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/checkbox.webp
rename to site/web/assets/images/docs/fwe/user-input/checkbox.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/chip.png b/site/web/assets/images/docs/fwe/user-input/chip.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/chip.png
rename to site/web/assets/images/docs/fwe/user-input/chip.png
diff --git a/src/content/assets/images/docs/fwe/user-input/dropdownmenu.webp b/site/web/assets/images/docs/fwe/user-input/dropdownmenu.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/dropdownmenu.webp
rename to site/web/assets/images/docs/fwe/user-input/dropdownmenu.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/material-buttons.png b/site/web/assets/images/docs/fwe/user-input/material-buttons.png
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/material-buttons.png
rename to site/web/assets/images/docs/fwe/user-input/material-buttons.png
diff --git a/src/content/assets/images/docs/fwe/user-input/segmented-button.webp b/site/web/assets/images/docs/fwe/user-input/segmented-button.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/segmented-button.webp
rename to site/web/assets/images/docs/fwe/user-input/segmented-button.webp
diff --git a/src/content/assets/images/docs/fwe/user-input/slider.webp b/site/web/assets/images/docs/fwe/user-input/slider.webp
similarity index 100%
rename from src/content/assets/images/docs/fwe/user-input/slider.webp
rename to site/web/assets/images/docs/fwe/user-input/slider.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/api-calls.webp b/site/web/assets/images/docs/get-started/android/react-native/api-calls.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/api-calls.webp
rename to site/web/assets/images/docs/get-started/android/react-native/api-calls.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/basic-layout.webp b/site/web/assets/images/docs/get-started/android/react-native/basic-layout.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/basic-layout.webp
rename to site/web/assets/images/docs/get-started/android/react-native/basic-layout.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/canvas.png b/site/web/assets/images/docs/get-started/android/react-native/canvas.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/canvas.png
rename to site/web/assets/images/docs/get-started/android/react-native/canvas.png
diff --git a/src/content/assets/images/docs/get-started/android/react-native/card-swipe.webp b/site/web/assets/images/docs/get-started/android/react-native/card-swipe.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/card-swipe.webp
rename to site/web/assets/images/docs/get-started/android/react-native/card-swipe.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/custom-cards.png b/site/web/assets/images/docs/get-started/android/react-native/custom-cards.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/custom-cards.png
rename to site/web/assets/images/docs/get-started/android/react-native/custom-cards.png
diff --git a/src/content/assets/images/docs/get-started/android/react-native/flatlist.webp b/site/web/assets/images/docs/get-started/android/react-native/flatlist.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/flatlist.webp
rename to site/web/assets/images/docs/get-started/android/react-native/flatlist.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/flutter-fade.webp b/site/web/assets/images/docs/get-started/android/react-native/flutter-fade.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/flutter-fade.webp
rename to site/web/assets/images/docs/get-started/android/react-native/flutter-fade.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/flutter-gestures.webp b/site/web/assets/images/docs/get-started/android/react-native/flutter-gestures.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/flutter-gestures.webp
rename to site/web/assets/images/docs/get-started/android/react-native/flutter-gestures.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/flutterstyling.webp b/site/web/assets/images/docs/get-started/android/react-native/flutterstyling.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/flutterstyling.webp
rename to site/web/assets/images/docs/get-started/android/react-native/flutterstyling.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/hello-world-basic.png b/site/web/assets/images/docs/get-started/android/react-native/hello-world-basic.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/hello-world-basic.png
rename to site/web/assets/images/docs/get-started/android/react-native/hello-world-basic.png
diff --git a/src/content/assets/images/docs/get-started/android/react-native/hello-world.png b/site/web/assets/images/docs/get-started/android/react-native/hello-world.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/hello-world.png
rename to site/web/assets/images/docs/get-started/android/react-native/hello-world.png
diff --git a/src/content/assets/images/docs/get-started/android/react-native/input-fields.webp b/site/web/assets/images/docs/get-started/android/react-native/input-fields.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/input-fields.webp
rename to site/web/assets/images/docs/get-started/android/react-native/input-fields.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/modular.png b/site/web/assets/images/docs/get-started/android/react-native/modular.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/modular.png
rename to site/web/assets/images/docs/get-started/android/react-native/modular.png
diff --git a/src/content/assets/images/docs/get-started/android/react-native/navigation.webp b/site/web/assets/images/docs/get-started/android/react-native/navigation.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/navigation.webp
rename to site/web/assets/images/docs/get-started/android/react-native/navigation.webp
diff --git a/src/content/assets/images/docs/get-started/android/react-native/stack.png b/site/web/assets/images/docs/get-started/android/react-native/stack.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/stack.png
rename to site/web/assets/images/docs/get-started/android/react-native/stack.png
diff --git a/src/content/assets/images/docs/get-started/android/react-native/state-change.webp b/site/web/assets/images/docs/get-started/android/react-native/state-change.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/android/react-native/state-change.webp
rename to site/web/assets/images/docs/get-started/android/react-native/state-change.webp
diff --git a/src/content/assets/images/docs/get-started/codelab-goal-background.jpg b/site/web/assets/images/docs/get-started/codelab-goal-background.jpg
similarity index 100%
rename from src/content/assets/images/docs/get-started/codelab-goal-background.jpg
rename to site/web/assets/images/docs/get-started/codelab-goal-background.jpg
diff --git a/src/content/assets/images/docs/get-started/hot-reload.svg b/site/web/assets/images/docs/get-started/hot-reload.svg
similarity index 100%
rename from src/content/assets/images/docs/get-started/hot-reload.svg
rename to site/web/assets/images/docs/get-started/hot-reload.svg
diff --git a/src/content/assets/images/docs/get-started/increment-button.png b/site/web/assets/images/docs/get-started/increment-button.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/increment-button.png
rename to site/web/assets/images/docs/get-started/increment-button.png
diff --git a/src/content/assets/images/docs/get-started/install_android_tools.png b/site/web/assets/images/docs/get-started/install_android_tools.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/install_android_tools.png
rename to site/web/assets/images/docs/get-started/install_android_tools.png
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/api-calls.webp b/site/web/assets/images/docs/get-started/ios/react-native/api-calls.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/api-calls.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/api-calls.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/basic-layout.webp b/site/web/assets/images/docs/get-started/ios/react-native/basic-layout.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/basic-layout.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/basic-layout.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/canvas.png b/site/web/assets/images/docs/get-started/ios/react-native/canvas.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/canvas.png
rename to site/web/assets/images/docs/get-started/ios/react-native/canvas.png
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/card-swipe.webp b/site/web/assets/images/docs/get-started/ios/react-native/card-swipe.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/card-swipe.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/card-swipe.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/custom-cards.png b/site/web/assets/images/docs/get-started/ios/react-native/custom-cards.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/custom-cards.png
rename to site/web/assets/images/docs/get-started/ios/react-native/custom-cards.png
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/flatlist.webp b/site/web/assets/images/docs/get-started/ios/react-native/flatlist.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/flatlist.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/flatlist.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/flutter-fade.webp b/site/web/assets/images/docs/get-started/ios/react-native/flutter-fade.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/flutter-fade.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/flutter-fade.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/flutter-gestures.webp b/site/web/assets/images/docs/get-started/ios/react-native/flutter-gestures.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/flutter-gestures.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/flutter-gestures.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/flutterstyling.webp b/site/web/assets/images/docs/get-started/ios/react-native/flutterstyling.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/flutterstyling.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/flutterstyling.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/hello-world-basic.png b/site/web/assets/images/docs/get-started/ios/react-native/hello-world-basic.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/hello-world-basic.png
rename to site/web/assets/images/docs/get-started/ios/react-native/hello-world-basic.png
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/hello-world.png b/site/web/assets/images/docs/get-started/ios/react-native/hello-world.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/hello-world.png
rename to site/web/assets/images/docs/get-started/ios/react-native/hello-world.png
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/input-fields.webp b/site/web/assets/images/docs/get-started/ios/react-native/input-fields.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/input-fields.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/input-fields.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/modular.png b/site/web/assets/images/docs/get-started/ios/react-native/modular.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/modular.png
rename to site/web/assets/images/docs/get-started/ios/react-native/modular.png
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/navigation.webp b/site/web/assets/images/docs/get-started/ios/react-native/navigation.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/navigation.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/navigation.webp
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/stack.png b/site/web/assets/images/docs/get-started/ios/react-native/stack.png
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/stack.png
rename to site/web/assets/images/docs/get-started/ios/react-native/stack.png
diff --git a/src/content/assets/images/docs/get-started/ios/react-native/state-change.webp b/site/web/assets/images/docs/get-started/ios/react-native/state-change.webp
similarity index 100%
rename from src/content/assets/images/docs/get-started/ios/react-native/state-change.webp
rename to site/web/assets/images/docs/get-started/ios/react-native/state-change.webp
diff --git a/src/content/assets/images/docs/homepage/_README.md b/site/web/assets/images/docs/homepage/_README.md
similarity index 100%
rename from src/content/assets/images/docs/homepage/_README.md
rename to site/web/assets/images/docs/homepage/_README.md
diff --git a/src/content/assets/images/docs/homepage/dart-diagram-small.png b/site/web/assets/images/docs/homepage/dart-diagram-small.png
similarity index 100%
rename from src/content/assets/images/docs/homepage/dart-diagram-small.png
rename to site/web/assets/images/docs/homepage/dart-diagram-small.png
diff --git a/src/content/assets/images/docs/homepage/reflectly-hero-600px.png b/site/web/assets/images/docs/homepage/reflectly-hero-600px.png
similarity index 100%
rename from src/content/assets/images/docs/homepage/reflectly-hero-600px.png
rename to site/web/assets/images/docs/homepage/reflectly-hero-600px.png
diff --git a/src/content/assets/images/docs/integration-test/migration-1.png b/site/web/assets/images/docs/integration-test/migration-1.png
similarity index 100%
rename from src/content/assets/images/docs/integration-test/migration-1.png
rename to site/web/assets/images/docs/integration-test/migration-1.png
diff --git a/src/content/assets/images/docs/integration-test/test-lab-1.png b/site/web/assets/images/docs/integration-test/test-lab-1.png
similarity index 100%
rename from src/content/assets/images/docs/integration-test/test-lab-1.png
rename to site/web/assets/images/docs/integration-test/test-lab-1.png
diff --git a/src/content/assets/images/docs/integration-test/test-lab-2.png b/site/web/assets/images/docs/integration-test/test-lab-2.png
similarity index 100%
rename from src/content/assets/images/docs/integration-test/test-lab-2.png
rename to site/web/assets/images/docs/integration-test/test-lab-2.png
diff --git a/src/content/assets/images/docs/integration-test/test-lab-3.png b/site/web/assets/images/docs/integration-test/test-lab-3.png
similarity index 100%
rename from src/content/assets/images/docs/integration-test/test-lab-3.png
rename to site/web/assets/images/docs/integration-test/test-lab-3.png
diff --git a/src/content/assets/images/docs/integration-test/test-lab-4.png b/site/web/assets/images/docs/integration-test/test-lab-4.png
similarity index 100%
rename from src/content/assets/images/docs/integration-test/test-lab-4.png
rename to site/web/assets/images/docs/integration-test/test-lab-4.png
diff --git a/src/content/assets/images/docs/logs.png b/site/web/assets/images/docs/logs.png
similarity index 100%
rename from src/content/assets/images/docs/logs.png
rename to site/web/assets/images/docs/logs.png
diff --git a/src/content/assets/images/docs/owl.jpg b/site/web/assets/images/docs/owl.jpg
similarity index 100%
rename from src/content/assets/images/docs/owl.jpg
rename to site/web/assets/images/docs/owl.jpg
diff --git a/src/content/assets/images/docs/perf/devtools-size.png b/site/web/assets/images/docs/perf/devtools-size.png
similarity index 100%
rename from src/content/assets/images/docs/perf/devtools-size.png
rename to site/web/assets/images/docs/perf/devtools-size.png
diff --git a/src/content/assets/images/docs/perf/size-summary.png b/site/web/assets/images/docs/perf/size-summary.png
similarity index 100%
rename from src/content/assets/images/docs/perf/size-summary.png
rename to site/web/assets/images/docs/perf/size-summary.png
diff --git a/src/content/assets/images/docs/perf/vital-size.png b/site/web/assets/images/docs/perf/vital-size.png
similarity index 100%
rename from src/content/assets/images/docs/perf/vital-size.png
rename to site/web/assets/images/docs/perf/vital-size.png
diff --git a/src/content/assets/images/docs/platform-adaptations/android-zoom-animation.png b/site/web/assets/images/docs/platform-adaptations/android-zoom-animation.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/android-zoom-animation.png
rename to site/web/assets/images/docs/platform-adaptations/android-zoom-animation.png
diff --git a/src/content/assets/images/docs/platform-adaptations/cupertino-alert.png b/site/web/assets/images/docs/platform-adaptations/cupertino-alert.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/cupertino-alert.png
rename to site/web/assets/images/docs/platform-adaptations/cupertino-alert.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-appbar.png b/site/web/assets/images/docs/platform-adaptations/hig-appbar.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-appbar.png
rename to site/web/assets/images/docs/platform-adaptations/hig-appbar.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-checkbox.png b/site/web/assets/images/docs/platform-adaptations/hig-checkbox.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-checkbox.png
rename to site/web/assets/images/docs/platform-adaptations/hig-checkbox.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-progress.png b/site/web/assets/images/docs/platform-adaptations/hig-progress.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-progress.png
rename to site/web/assets/images/docs/platform-adaptations/hig-progress.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-radio.png b/site/web/assets/images/docs/platform-adaptations/hig-radio.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-radio.png
rename to site/web/assets/images/docs/platform-adaptations/hig-radio.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-refresh.png b/site/web/assets/images/docs/platform-adaptations/hig-refresh.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-refresh.png
rename to site/web/assets/images/docs/platform-adaptations/hig-refresh.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-slider.png b/site/web/assets/images/docs/platform-adaptations/hig-slider.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-slider.png
rename to site/web/assets/images/docs/platform-adaptations/hig-slider.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-switch.png b/site/web/assets/images/docs/platform-adaptations/hig-switch.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-switch.png
rename to site/web/assets/images/docs/platform-adaptations/hig-switch.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-tabbar.png b/site/web/assets/images/docs/platform-adaptations/hig-tabbar.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-tabbar.png
rename to site/web/assets/images/docs/platform-adaptations/hig-tabbar.png
diff --git a/src/content/assets/images/docs/platform-adaptations/hig-text-field.png b/site/web/assets/images/docs/platform-adaptations/hig-text-field.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/hig-text-field.png
rename to site/web/assets/images/docs/platform-adaptations/hig-text-field.png
diff --git a/src/content/assets/images/docs/platform-adaptations/iconography-android.png b/site/web/assets/images/docs/platform-adaptations/iconography-android.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/iconography-android.png
rename to site/web/assets/images/docs/platform-adaptations/iconography-android.png
diff --git a/src/content/assets/images/docs/platform-adaptations/iconography-ios.png b/site/web/assets/images/docs/platform-adaptations/iconography-ios.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/iconography-ios.png
rename to site/web/assets/images/docs/platform-adaptations/iconography-ios.png
diff --git a/src/content/assets/images/docs/platform-adaptations/m3-alert.png b/site/web/assets/images/docs/platform-adaptations/m3-alert.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/m3-alert.png
rename to site/web/assets/images/docs/platform-adaptations/m3-alert.png
diff --git a/src/content/assets/images/docs/platform-adaptations/m3-checkbox.png b/site/web/assets/images/docs/platform-adaptations/m3-checkbox.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/m3-checkbox.png
rename to site/web/assets/images/docs/platform-adaptations/m3-checkbox.png
diff --git a/src/content/assets/images/docs/platform-adaptations/m3-progress.png b/site/web/assets/images/docs/platform-adaptations/m3-progress.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/m3-progress.png
rename to site/web/assets/images/docs/platform-adaptations/m3-progress.png
diff --git a/src/content/assets/images/docs/platform-adaptations/m3-radio.png b/site/web/assets/images/docs/platform-adaptations/m3-radio.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/m3-radio.png
rename to site/web/assets/images/docs/platform-adaptations/m3-radio.png
diff --git a/src/content/assets/images/docs/platform-adaptations/m3-refresh.png b/site/web/assets/images/docs/platform-adaptations/m3-refresh.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/m3-refresh.png
rename to site/web/assets/images/docs/platform-adaptations/m3-refresh.png
diff --git a/src/content/assets/images/docs/platform-adaptations/m3-slider.png b/site/web/assets/images/docs/platform-adaptations/m3-slider.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/m3-slider.png
rename to site/web/assets/images/docs/platform-adaptations/m3-slider.png
diff --git a/src/content/assets/images/docs/platform-adaptations/m3-switch.png b/site/web/assets/images/docs/platform-adaptations/m3-switch.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/m3-switch.png
rename to site/web/assets/images/docs/platform-adaptations/m3-switch.png
diff --git a/src/content/assets/images/docs/platform-adaptations/m3-text-field.png b/site/web/assets/images/docs/platform-adaptations/m3-text-field.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/m3-text-field.png
rename to site/web/assets/images/docs/platform-adaptations/m3-text-field.png
diff --git a/src/content/assets/images/docs/platform-adaptations/mat-appbar.png b/site/web/assets/images/docs/platform-adaptations/mat-appbar.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/mat-appbar.png
rename to site/web/assets/images/docs/platform-adaptations/mat-appbar.png
diff --git a/src/content/assets/images/docs/platform-adaptations/mat-navbar.png b/site/web/assets/images/docs/platform-adaptations/mat-navbar.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/mat-navbar.png
rename to site/web/assets/images/docs/platform-adaptations/mat-navbar.png
diff --git a/src/content/assets/images/docs/platform-adaptations/navigation-android-back.webp b/site/web/assets/images/docs/platform-adaptations/navigation-android-back.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/navigation-android-back.webp
rename to site/web/assets/images/docs/platform-adaptations/navigation-android-back.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/navigation-android-p.webp b/site/web/assets/images/docs/platform-adaptations/navigation-android-p.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/navigation-android-p.webp
rename to site/web/assets/images/docs/platform-adaptations/navigation-android-p.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/navigation-android-q.webp b/site/web/assets/images/docs/platform-adaptations/navigation-android-q.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/navigation-android-q.webp
rename to site/web/assets/images/docs/platform-adaptations/navigation-android-q.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/navigation-android.webp b/site/web/assets/images/docs/platform-adaptations/navigation-android.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/navigation-android.webp
rename to site/web/assets/images/docs/platform-adaptations/navigation-android.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/navigation-ios-back.webp b/site/web/assets/images/docs/platform-adaptations/navigation-ios-back.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/navigation-ios-back.webp
rename to site/web/assets/images/docs/platform-adaptations/navigation-ios-back.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/navigation-ios-modal.webp b/site/web/assets/images/docs/platform-adaptations/navigation-ios-modal.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/navigation-ios-modal.webp
rename to site/web/assets/images/docs/platform-adaptations/navigation-ios-modal.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/navigation-ios-nav-bar.webp b/site/web/assets/images/docs/platform-adaptations/navigation-ios-nav-bar.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/navigation-ios-nav-bar.webp
rename to site/web/assets/images/docs/platform-adaptations/navigation-ios-nav-bar.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/navigation-ios.webp b/site/web/assets/images/docs/platform-adaptations/navigation-ios.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/navigation-ios.webp
rename to site/web/assets/images/docs/platform-adaptations/navigation-ios.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/scroll-medium.webp b/site/web/assets/images/docs/platform-adaptations/scroll-medium.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/scroll-medium.webp
rename to site/web/assets/images/docs/platform-adaptations/scroll-medium.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/scroll-momentum-ios.webp b/site/web/assets/images/docs/platform-adaptations/scroll-momentum-ios.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/scroll-momentum-ios.webp
rename to site/web/assets/images/docs/platform-adaptations/scroll-momentum-ios.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/scroll-overscroll.webp b/site/web/assets/images/docs/platform-adaptations/scroll-overscroll.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/scroll-overscroll.webp
rename to site/web/assets/images/docs/platform-adaptations/scroll-overscroll.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/scroll-soft.webp b/site/web/assets/images/docs/platform-adaptations/scroll-soft.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/scroll-soft.webp
rename to site/web/assets/images/docs/platform-adaptations/scroll-soft.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/scroll-static-overscroll.webp b/site/web/assets/images/docs/platform-adaptations/scroll-static-overscroll.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/scroll-static-overscroll.webp
rename to site/web/assets/images/docs/platform-adaptations/scroll-static-overscroll.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/scroll-strong.webp b/site/web/assets/images/docs/platform-adaptations/scroll-strong.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/scroll-strong.webp
rename to site/web/assets/images/docs/platform-adaptations/scroll-strong.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/scroll-tap-to-top-ios.webp b/site/web/assets/images/docs/platform-adaptations/scroll-tap-to-top-ios.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/scroll-tap-to-top-ios.webp
rename to site/web/assets/images/docs/platform-adaptations/scroll-tap-to-top-ios.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-double-tap-android.webp b/site/web/assets/images/docs/platform-adaptations/text-double-tap-android.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-double-tap-android.webp
rename to site/web/assets/images/docs/platform-adaptations/text-double-tap-android.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-double-tap-ios.webp b/site/web/assets/images/docs/platform-adaptations/text-double-tap-ios.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-double-tap-ios.webp
rename to site/web/assets/images/docs/platform-adaptations/text-double-tap-ios.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-keyboard-move-android.webp b/site/web/assets/images/docs/platform-adaptations/text-keyboard-move-android.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-keyboard-move-android.webp
rename to site/web/assets/images/docs/platform-adaptations/text-keyboard-move-android.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-keyboard-move-ios.webp b/site/web/assets/images/docs/platform-adaptations/text-keyboard-move-ios.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-keyboard-move-ios.webp
rename to site/web/assets/images/docs/platform-adaptations/text-keyboard-move-ios.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-long-press-android.webp b/site/web/assets/images/docs/platform-adaptations/text-long-press-android.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-long-press-android.webp
rename to site/web/assets/images/docs/platform-adaptations/text-long-press-android.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-long-press-drag-android.webp b/site/web/assets/images/docs/platform-adaptations/text-long-press-drag-android.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-long-press-drag-android.webp
rename to site/web/assets/images/docs/platform-adaptations/text-long-press-drag-android.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-long-press-drag-ios.webp b/site/web/assets/images/docs/platform-adaptations/text-long-press-drag-ios.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-long-press-drag-ios.webp
rename to site/web/assets/images/docs/platform-adaptations/text-long-press-drag-ios.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-long-press-ios.webp b/site/web/assets/images/docs/platform-adaptations/text-long-press-ios.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-long-press-ios.webp
rename to site/web/assets/images/docs/platform-adaptations/text-long-press-ios.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-single-tap-android.webp b/site/web/assets/images/docs/platform-adaptations/text-single-tap-android.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-single-tap-android.webp
rename to site/web/assets/images/docs/platform-adaptations/text-single-tap-android.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-single-tap-ios.webp b/site/web/assets/images/docs/platform-adaptations/text-single-tap-ios.webp
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-single-tap-ios.webp
rename to site/web/assets/images/docs/platform-adaptations/text-single-tap-ios.webp
diff --git a/src/content/assets/images/docs/platform-adaptations/text-toolbar-android.png b/site/web/assets/images/docs/platform-adaptations/text-toolbar-android.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-toolbar-android.png
rename to site/web/assets/images/docs/platform-adaptations/text-toolbar-android.png
diff --git a/src/content/assets/images/docs/platform-adaptations/text-toolbar-ios.png b/site/web/assets/images/docs/platform-adaptations/text-toolbar-ios.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/text-toolbar-ios.png
rename to site/web/assets/images/docs/platform-adaptations/text-toolbar-ios.png
diff --git a/src/content/assets/images/docs/platform-adaptations/typography-android.png b/site/web/assets/images/docs/platform-adaptations/typography-android.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/typography-android.png
rename to site/web/assets/images/docs/platform-adaptations/typography-android.png
diff --git a/src/content/assets/images/docs/platform-adaptations/typography-ios.png b/site/web/assets/images/docs/platform-adaptations/typography-ios.png
similarity index 100%
rename from src/content/assets/images/docs/platform-adaptations/typography-ios.png
rename to site/web/assets/images/docs/platform-adaptations/typography-ios.png
diff --git a/src/content/assets/images/docs/releaseguide/android-studio-flamingo-gradle-upgrade.png b/site/web/assets/images/docs/releaseguide/android-studio-flamingo-gradle-upgrade.png
similarity index 100%
rename from src/content/assets/images/docs/releaseguide/android-studio-flamingo-gradle-upgrade.png
rename to site/web/assets/images/docs/releaseguide/android-studio-flamingo-gradle-upgrade.png
diff --git a/src/content/assets/images/docs/releaseguide/android-studio-flamingo-upgrade-alert.png b/site/web/assets/images/docs/releaseguide/android-studio-flamingo-upgrade-alert.png
similarity index 100%
rename from src/content/assets/images/docs/releaseguide/android-studio-flamingo-upgrade-alert.png
rename to site/web/assets/images/docs/releaseguide/android-studio-flamingo-upgrade-alert.png
diff --git a/src/content/assets/images/docs/releaseguide/macos_xcode_settings.png b/site/web/assets/images/docs/releaseguide/macos_xcode_settings.png
similarity index 100%
rename from src/content/assets/images/docs/releaseguide/macos_xcode_settings.png
rename to site/web/assets/images/docs/releaseguide/macos_xcode_settings.png
diff --git a/src/content/assets/images/docs/releaseguide/xcode_settings.png b/site/web/assets/images/docs/releaseguide/xcode_settings.png
similarity index 100%
rename from src/content/assets/images/docs/releaseguide/xcode_settings.png
rename to site/web/assets/images/docs/releaseguide/xcode_settings.png
diff --git a/src/content/assets/images/docs/releaseguide/xcode_workflow_branch_changes.png b/site/web/assets/images/docs/releaseguide/xcode_workflow_branch_changes.png
similarity index 100%
rename from src/content/assets/images/docs/releaseguide/xcode_workflow_branch_changes.png
rename to site/web/assets/images/docs/releaseguide/xcode_workflow_branch_changes.png
diff --git a/src/content/assets/images/docs/resources/_README.md b/site/web/assets/images/docs/resources/_README.md
similarity index 100%
rename from src/content/assets/images/docs/resources/_README.md
rename to site/web/assets/images/docs/resources/_README.md
diff --git a/src/content/assets/images/docs/resources/diagram-layercake.png b/site/web/assets/images/docs/resources/diagram-layercake.png
similarity index 100%
rename from src/content/assets/images/docs/resources/diagram-layercake.png
rename to site/web/assets/images/docs/resources/diagram-layercake.png
diff --git a/src/content/assets/images/docs/setup/trust-computer.png b/site/web/assets/images/docs/setup/trust-computer.png
similarity index 100%
rename from src/content/assets/images/docs/setup/trust-computer.png
rename to site/web/assets/images/docs/setup/trust-computer.png
diff --git a/src/content/assets/images/docs/setup/xcode-account.png b/site/web/assets/images/docs/setup/xcode-account.png
similarity index 100%
rename from src/content/assets/images/docs/setup/xcode-account.png
rename to site/web/assets/images/docs/setup/xcode-account.png
diff --git a/src/content/assets/images/docs/setup/xcode-unique-bundle-id.png b/site/web/assets/images/docs/setup/xcode-unique-bundle-id.png
similarity index 100%
rename from src/content/assets/images/docs/setup/xcode-unique-bundle-id.png
rename to site/web/assets/images/docs/setup/xcode-unique-bundle-id.png
diff --git a/src/content/assets/images/docs/testing/debugging/attach-flutter-process-field.png b/site/web/assets/images/docs/testing/debugging/attach-flutter-process-field.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/attach-flutter-process-field.png
rename to site/web/assets/images/docs/testing/debugging/attach-flutter-process-field.png
diff --git a/src/content/assets/images/docs/testing/debugging/ios.png b/site/web/assets/images/docs/testing/debugging/ios.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/ios.png
rename to site/web/assets/images/docs/testing/debugging/ios.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/android-studio/attach-process-button.png b/site/web/assets/images/docs/testing/debugging/native/android-studio/attach-process-button.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/android-studio/attach-process-button.png
rename to site/web/assets/images/docs/testing/debugging/native/android-studio/attach-process-button.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/android-studio/attach-process-dialog.png b/site/web/assets/images/docs/testing/debugging/native/android-studio/attach-process-dialog.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/android-studio/attach-process-dialog.png
rename to site/web/assets/images/docs/testing/debugging/native/android-studio/attach-process-dialog.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/android-studio/debug-open-java-code.png b/site/web/assets/images/docs/testing/debugging/native/android-studio/debug-open-java-code.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/android-studio/debug-open-java-code.png
rename to site/web/assets/images/docs/testing/debugging/native/android-studio/debug-open-java-code.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/android-studio/debug-run.png b/site/web/assets/images/docs/testing/debugging/native/android-studio/debug-run.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/android-studio/debug-run.png
rename to site/web/assets/images/docs/testing/debugging/native/android-studio/debug-run.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/android-studio/debugger-active.png b/site/web/assets/images/docs/testing/debugging/native/android-studio/debugger-active.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/android-studio/debugger-active.png
rename to site/web/assets/images/docs/testing/debugging/native/android-studio/debugger-active.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/dart-debugger.png b/site/web/assets/images/docs/testing/debugging/native/dart-debugger.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/dart-debugger.png
rename to site/web/assets/images/docs/testing/debugging/native/dart-debugger.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/macos/basic-app.png b/site/web/assets/images/docs/testing/debugging/native/macos/basic-app.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/macos/basic-app.png
rename to site/web/assets/images/docs/testing/debugging/native/macos/basic-app.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/url-launcher-app/android.png b/site/web/assets/images/docs/testing/debugging/native/url-launcher-app/android.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/url-launcher-app/android.png
rename to site/web/assets/images/docs/testing/debugging/native/url-launcher-app/android.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/url-launcher-app/ios.png b/site/web/assets/images/docs/testing/debugging/native/url-launcher-app/ios.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/url-launcher-app/ios.png
rename to site/web/assets/images/docs/testing/debugging/native/url-launcher-app/ios.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/url-launcher-app/windows.png b/site/web/assets/images/docs/testing/debugging/native/url-launcher-app/windows.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/url-launcher-app/windows.png
rename to site/web/assets/images/docs/testing/debugging/native/url-launcher-app/windows.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/visual-studio/attach-to-process-dialog.png b/site/web/assets/images/docs/testing/debugging/native/visual-studio/attach-to-process-dialog.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/visual-studio/attach-to-process-dialog.png
rename to site/web/assets/images/docs/testing/debugging/native/visual-studio/attach-to-process-dialog.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/visual-studio/choose-solution.png b/site/web/assets/images/docs/testing/debugging/native/visual-studio/choose-solution.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/visual-studio/choose-solution.png
rename to site/web/assets/images/docs/testing/debugging/native/visual-studio/choose-solution.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/visual-studio/debugger-active.png b/site/web/assets/images/docs/testing/debugging/native/visual-studio/debugger-active.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/visual-studio/debugger-active.png
rename to site/web/assets/images/docs/testing/debugging/native/visual-studio/debugger-active.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/xcode/dart-vm-uri.png b/site/web/assets/images/docs/testing/debugging/native/xcode/dart-vm-uri.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/xcode/dart-vm-uri.png
rename to site/web/assets/images/docs/testing/debugging/native/xcode/dart-vm-uri.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/xcode/run-app.png b/site/web/assets/images/docs/testing/debugging/native/xcode/run-app.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/xcode/run-app.png
rename to site/web/assets/images/docs/testing/debugging/native/xcode/run-app.png
diff --git a/src/content/assets/images/docs/testing/debugging/native/xcode/select-device.png b/site/web/assets/images/docs/testing/debugging/native/xcode/select-device.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/native/xcode/select-device.png
rename to site/web/assets/images/docs/testing/debugging/native/xcode/select-device.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/debug.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/debug.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/debug.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/debug.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/hot-reload.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/hot-reload.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/hot-reload.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/hot-reload.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/hot-restart.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/hot-restart.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/hot-restart.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/hot-restart.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/inspector.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/inspector.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/inspector.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/inspector.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/pause.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/pause.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/pause.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/pause.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/play-or-resume.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/play-or-resume.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/play-or-resume.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/play-or-resume.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/step-into.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/step-into.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/step-into.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/step-into.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/step-out.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/step-out.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/step-out.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/step-out.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/step-over.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/step-over.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/step-over.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/step-over.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/icons/stop.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/icons/stop.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/icons/stop.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/icons/stop.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/attach-flutter-process-menu.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/attach-flutter-process-menu.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/attach-flutter-process-menu.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/attach-flutter-process-menu.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/debug-toolbar.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/debug-toolbar.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/debug-toolbar.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/debug-toolbar.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/debugger-parts.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/debugger-parts.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/debugger-parts.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/debugger-parts.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-success.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-success.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-success.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-success.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri-filled.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri-filled.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri-filled.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri-filled.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-debugger-paused.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-debugger-paused.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-debugger-paused.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-debugger-paused.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-debugger.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-debugger.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-debugger.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-debugger.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-layout-explorer.png b/site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-layout-explorer.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-layout-explorer.png
rename to site/web/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-layout-explorer.png
diff --git a/src/content/assets/images/docs/testing/debugging/vscode-widget-details-tree.png b/site/web/assets/images/docs/testing/debugging/vscode-widget-details-tree.png
similarity index 100%
rename from src/content/assets/images/docs/testing/debugging/vscode-widget-details-tree.png
rename to site/web/assets/images/docs/testing/debugging/vscode-widget-details-tree.png
diff --git a/src/content/assets/images/docs/tools/android-studio/README b/site/web/assets/images/docs/tools/android-studio/README
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/README
rename to site/web/assets/images/docs/tools/android-studio/README
diff --git a/src/content/assets/images/docs/tools/android-studio/assists.webp b/site/web/assets/images/docs/tools/android-studio/assists.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/assists.webp
rename to site/web/assets/images/docs/tools/android-studio/assists.webp
diff --git a/src/content/assets/images/docs/tools/android-studio/dart-analysis.png b/site/web/assets/images/docs/tools/android-studio/dart-analysis.png
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/dart-analysis.png
rename to site/web/assets/images/docs/tools/android-studio/dart-analysis.png
diff --git a/src/content/assets/images/docs/tools/android-studio/hot-reload.gif b/site/web/assets/images/docs/tools/android-studio/hot-reload.gif
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/hot-reload.gif
rename to site/web/assets/images/docs/tools/android-studio/hot-reload.gif
diff --git a/src/content/assets/images/docs/tools/android-studio/hot-reload.webp b/site/web/assets/images/docs/tools/android-studio/hot-reload.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/hot-reload.webp
rename to site/web/assets/images/docs/tools/android-studio/hot-reload.webp
diff --git a/src/content/assets/images/docs/tools/android-studio/inspector_select_example.webp b/site/web/assets/images/docs/tools/android-studio/inspector_select_example.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/inspector_select_example.webp
rename to site/web/assets/images/docs/tools/android-studio/inspector_select_example.webp
diff --git a/src/content/assets/images/docs/tools/android-studio/keymap-settings-flutter-plugin.png b/site/web/assets/images/docs/tools/android-studio/keymap-settings-flutter-plugin.png
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/keymap-settings-flutter-plugin.png
rename to site/web/assets/images/docs/tools/android-studio/keymap-settings-flutter-plugin.png
diff --git a/src/content/assets/images/docs/tools/android-studio/log.png b/site/web/assets/images/docs/tools/android-studio/log.png
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/log.png
rename to site/web/assets/images/docs/tools/android-studio/log.png
diff --git a/src/content/assets/images/docs/tools/android-studio/main-toolbar.png b/site/web/assets/images/docs/tools/android-studio/main-toolbar.png
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/main-toolbar.png
rename to site/web/assets/images/docs/tools/android-studio/main-toolbar.png
diff --git a/src/content/assets/images/docs/tools/android-studio/switch_inspector_tree.webp b/site/web/assets/images/docs/tools/android-studio/switch_inspector_tree.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/switch_inspector_tree.webp
rename to site/web/assets/images/docs/tools/android-studio/switch_inspector_tree.webp
diff --git a/src/content/assets/images/docs/tools/android-studio/templates.webp b/site/web/assets/images/docs/tools/android-studio/templates.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/templates.webp
rename to site/web/assets/images/docs/tools/android-studio/templates.webp
diff --git a/src/content/assets/images/docs/tools/android-studio/widget-rebuild-info.png b/site/web/assets/images/docs/tools/android-studio/widget-rebuild-info.png
similarity index 100%
rename from src/content/assets/images/docs/tools/android-studio/widget-rebuild-info.png
rename to site/web/assets/images/docs/tools/android-studio/widget-rebuild-info.png
diff --git a/src/content/assets/images/docs/tools/devtools/android_studio_open_devtools.png b/site/web/assets/images/docs/tools/devtools/android_studio_open_devtools.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/android_studio_open_devtools.png
rename to site/web/assets/images/docs/tools/devtools/android_studio_open_devtools.png
diff --git a/src/content/assets/images/docs/tools/devtools/app_size_access_landing_page.png b/site/web/assets/images/docs/tools/devtools/app_size_access_landing_page.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/app_size_access_landing_page.png
rename to site/web/assets/images/docs/tools/devtools/app_size_access_landing_page.png
diff --git a/src/content/assets/images/docs/tools/devtools/app_size_analysis.png b/site/web/assets/images/docs/tools/devtools/app_size_analysis.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/app_size_analysis.png
rename to site/web/assets/images/docs/tools/devtools/app_size_analysis.png
diff --git a/src/content/assets/images/docs/tools/devtools/app_size_call_graph.png b/site/web/assets/images/docs/tools/devtools/app_size_call_graph.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/app_size_call_graph.png
rename to site/web/assets/images/docs/tools/devtools/app_size_call_graph.png
diff --git a/src/content/assets/images/docs/tools/devtools/app_size_diff.png b/site/web/assets/images/docs/tools/devtools/app_size_diff.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/app_size_diff.png
rename to site/web/assets/images/docs/tools/devtools/app_size_diff.png
diff --git a/src/content/assets/images/docs/tools/devtools/app_size_dominator_tree.png b/site/web/assets/images/docs/tools/devtools/app_size_dominator_tree.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/app_size_dominator_tree.png
rename to site/web/assets/images/docs/tools/devtools/app_size_dominator_tree.png
diff --git a/src/content/assets/images/docs/tools/devtools/app_size_load_analysis.png b/site/web/assets/images/docs/tools/devtools/app_size_load_analysis.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/app_size_load_analysis.png
rename to site/web/assets/images/docs/tools/devtools/app_size_load_analysis.png
diff --git a/src/content/assets/images/docs/tools/devtools/app_size_load_diff.png b/site/web/assets/images/docs/tools/devtools/app_size_load_diff.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/app_size_load_diff.png
rename to site/web/assets/images/docs/tools/devtools/app_size_load_diff.png
diff --git a/src/content/assets/images/docs/tools/devtools/app_size_tab.png b/site/web/assets/images/docs/tools/devtools/app_size_tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/app_size_tab.png
rename to site/web/assets/images/docs/tools/devtools/app_size_tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/bottom-up-view.png b/site/web/assets/images/docs/tools/devtools/bottom-up-view.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/bottom-up-view.png
rename to site/web/assets/images/docs/tools/devtools/bottom-up-view.png
diff --git a/src/content/assets/images/docs/tools/devtools/browse-heap-snapshot.png b/site/web/assets/images/docs/tools/devtools/browse-heap-snapshot.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/browse-heap-snapshot.png
rename to site/web/assets/images/docs/tools/devtools/browse-heap-snapshot.png
diff --git a/src/content/assets/images/docs/tools/devtools/call-tree.png b/site/web/assets/images/docs/tools/devtools/call-tree.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/call-tree.png
rename to site/web/assets/images/docs/tools/devtools/call-tree.png
diff --git a/src/content/assets/images/docs/tools/devtools/chrome-devtools-performance-panel.png b/site/web/assets/images/docs/tools/devtools/chrome-devtools-performance-panel.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/chrome-devtools-performance-panel.png
rename to site/web/assets/images/docs/tools/devtools/chrome-devtools-performance-panel.png
diff --git a/src/content/assets/images/docs/tools/devtools/connect_dialog.png b/site/web/assets/images/docs/tools/devtools/connect_dialog.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/connect_dialog.png
rename to site/web/assets/images/docs/tools/devtools/connect_dialog.png
diff --git a/src/content/assets/images/docs/tools/devtools/console-evaluate-expressions.png b/site/web/assets/images/docs/tools/devtools/console-evaluate-expressions.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/console-evaluate-expressions.png
rename to site/web/assets/images/docs/tools/devtools/console-evaluate-expressions.png
diff --git a/src/content/assets/images/docs/tools/devtools/console-evaluate-variables.png b/site/web/assets/images/docs/tools/devtools/console-evaluate-variables.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/console-evaluate-variables.png
rename to site/web/assets/images/docs/tools/devtools/console-evaluate-variables.png
diff --git a/src/content/assets/images/docs/tools/devtools/console-inspect-widget.png b/site/web/assets/images/docs/tools/devtools/console-inspect-widget.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/console-inspect-widget.png
rename to site/web/assets/images/docs/tools/devtools/console-inspect-widget.png
diff --git a/src/content/assets/images/docs/tools/devtools/console-references.png b/site/web/assets/images/docs/tools/devtools/console-references.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/console-references.png
rename to site/web/assets/images/docs/tools/devtools/console-references.png
diff --git a/src/content/assets/images/docs/tools/devtools/console-stdout.png b/site/web/assets/images/docs/tools/devtools/console-stdout.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/console-stdout.png
rename to site/web/assets/images/docs/tools/devtools/console-stdout.png
diff --git a/src/content/assets/images/docs/tools/devtools/cpu-flame-chart.png b/site/web/assets/images/docs/tools/devtools/cpu-flame-chart.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/cpu-flame-chart.png
rename to site/web/assets/images/docs/tools/devtools/cpu-flame-chart.png
diff --git a/src/content/assets/images/docs/tools/devtools/cpu-sampling-rate-menu.png b/site/web/assets/images/docs/tools/devtools/cpu-sampling-rate-menu.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/cpu-sampling-rate-menu.png
rename to site/web/assets/images/docs/tools/devtools/cpu-sampling-rate-menu.png
diff --git a/src/content/assets/images/docs/tools/devtools/dart-devtools.webp b/site/web/assets/images/docs/tools/devtools/dart-devtools.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/dart-devtools.webp
rename to site/web/assets/images/docs/tools/devtools/dart-devtools.webp
diff --git a/src/content/assets/images/docs/tools/devtools/debug-console.png b/site/web/assets/images/docs/tools/devtools/debug-console.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-console.png
rename to site/web/assets/images/docs/tools/devtools/debug-console.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-mode-banner-icon.png b/site/web/assets/images/docs/tools/devtools/debug-mode-banner-icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-mode-banner-icon.png
rename to site/web/assets/images/docs/tools/devtools/debug-mode-banner-icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-paint-mode-icon.png b/site/web/assets/images/docs/tools/devtools/debug-paint-mode-icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-paint-mode-icon.png
rename to site/web/assets/images/docs/tools/devtools/debug-paint-mode-icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guideline-render-box.png b/site/web/assets/images/docs/tools/devtools/debug-toggle-guideline-render-box.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guideline-render-box.png
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guideline-render-box.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-alignment.png b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-alignment.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-alignment.png
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-alignment.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-baseline.png b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-baseline.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-baseline.png
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-baseline.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-clip.png b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-clip.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-clip.png
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-clip.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-oversized.png b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-oversized.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-oversized.png
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-oversized.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-padding.png b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-padding.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-padding.png
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-padding.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-repaint-1.webp b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-repaint-1.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-repaint-1.webp
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-repaint-1.webp
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-repaint-2.webp b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-repaint-2.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-repaint-2.webp
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-repaint-2.webp
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-scroll.png b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-scroll.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-scroll.png
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-scroll.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-spacer.png b/site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-spacer.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-guidelines-spacer.png
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-guidelines-spacer.png
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-slow-animations-disabled.webp b/site/web/assets/images/docs/tools/devtools/debug-toggle-slow-animations-disabled.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-slow-animations-disabled.webp
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-slow-animations-disabled.webp
diff --git a/src/content/assets/images/docs/tools/devtools/debug-toggle-slow-animations-enabled.webp b/site/web/assets/images/docs/tools/devtools/debug-toggle-slow-animations-enabled.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debug-toggle-slow-animations-enabled.webp
rename to site/web/assets/images/docs/tools/devtools/debug-toggle-slow-animations-enabled.webp
diff --git a/src/content/assets/images/docs/tools/devtools/debugger_screenshot.png b/site/web/assets/images/docs/tools/devtools/debugger_screenshot.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/debugger_screenshot.png
rename to site/web/assets/images/docs/tools/devtools/debugger_screenshot.png
diff --git a/src/content/assets/images/docs/tools/devtools/deep-link-validator.png b/site/web/assets/images/docs/tools/devtools/deep-link-validator.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/deep-link-validator.png
rename to site/web/assets/images/docs/tools/devtools/deep-link-validator.png
diff --git a/src/content/assets/images/docs/tools/devtools/diff-tab.png b/site/web/assets/images/docs/tools/devtools/diff-tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/diff-tab.png
rename to site/web/assets/images/docs/tools/devtools/diff-tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/display-options.png b/site/web/assets/images/docs/tools/devtools/display-options.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/display-options.png
rename to site/web/assets/images/docs/tools/devtools/display-options.png
diff --git a/src/content/assets/images/docs/tools/devtools/enhanced-tracing.png b/site/web/assets/images/docs/tools/devtools/enhanced-tracing.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/enhanced-tracing.png
rename to site/web/assets/images/docs/tools/devtools/enhanced-tracing.png
diff --git a/src/content/assets/images/docs/tools/devtools/extension_dialog.png b/site/web/assets/images/docs/tools/devtools/extension_dialog.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/extension_dialog.png
rename to site/web/assets/images/docs/tools/devtools/extension_dialog.png
diff --git a/src/content/assets/images/docs/tools/devtools/extension_dialog_button.png b/site/web/assets/images/docs/tools/devtools/extension_dialog_button.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/extension_dialog_button.png
rename to site/web/assets/images/docs/tools/devtools/extension_dialog_button.png
diff --git a/src/content/assets/images/docs/tools/devtools/extension_enable_prompt.png b/site/web/assets/images/docs/tools/devtools/extension_enable_prompt.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/extension_enable_prompt.png
rename to site/web/assets/images/docs/tools/devtools/extension_enable_prompt.png
diff --git a/src/content/assets/images/docs/tools/devtools/filter-by-tag.png b/site/web/assets/images/docs/tools/devtools/filter-by-tag.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/filter-by-tag.png
rename to site/web/assets/images/docs/tools/devtools/filter-by-tag.png
diff --git a/src/content/assets/images/docs/tools/devtools/filter-ui.png b/site/web/assets/images/docs/tools/devtools/filter-ui.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/filter-ui.png
rename to site/web/assets/images/docs/tools/devtools/filter-ui.png
diff --git a/src/content/assets/images/docs/tools/devtools/flame-chart-help.png b/site/web/assets/images/docs/tools/devtools/flame-chart-help.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/flame-chart-help.png
rename to site/web/assets/images/docs/tools/devtools/flame-chart-help.png
diff --git a/src/content/assets/images/docs/tools/devtools/flex-explorer-tab.png b/site/web/assets/images/docs/tools/devtools/flex-explorer-tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/flex-explorer-tab.png
rename to site/web/assets/images/docs/tools/devtools/flex-explorer-tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/flutter-frames-chart.png b/site/web/assets/images/docs/tools/devtools/flutter-frames-chart.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/flutter-frames-chart.png
rename to site/web/assets/images/docs/tools/devtools/flutter-frames-chart.png
diff --git a/src/content/assets/images/docs/tools/devtools/flutter-inspector-settings.png b/site/web/assets/images/docs/tools/devtools/flutter-inspector-settings.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/flutter-inspector-settings.png
rename to site/web/assets/images/docs/tools/devtools/flutter-inspector-settings.png
diff --git a/src/content/assets/images/docs/tools/devtools/frame-analysis-tab.png b/site/web/assets/images/docs/tools/devtools/frame-analysis-tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/frame-analysis-tab.png
rename to site/web/assets/images/docs/tools/devtools/frame-analysis-tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/inspector-widget-explorer.png b/site/web/assets/images/docs/tools/devtools/inspector-widget-explorer.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/inspector-widget-explorer.png
rename to site/web/assets/images/docs/tools/devtools/inspector-widget-explorer.png
diff --git a/src/content/assets/images/docs/tools/devtools/inspector-widget-tree.png b/site/web/assets/images/docs/tools/devtools/inspector-widget-tree.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/inspector-widget-tree.png
rename to site/web/assets/images/docs/tools/devtools/inspector-widget-tree.png
diff --git a/src/content/assets/images/docs/tools/devtools/inspector_details_tree.png b/site/web/assets/images/docs/tools/devtools/inspector_details_tree.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/inspector_details_tree.png
rename to site/web/assets/images/docs/tools/devtools/inspector_details_tree.png
diff --git a/src/content/assets/images/docs/tools/devtools/inspector_legacy_screenshot.png b/site/web/assets/images/docs/tools/devtools/inspector_legacy_screenshot.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/inspector_legacy_screenshot.png
rename to site/web/assets/images/docs/tools/devtools/inspector_legacy_screenshot.png
diff --git a/src/content/assets/images/docs/tools/devtools/inspector_screenshot.png b/site/web/assets/images/docs/tools/devtools/inspector_screenshot.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/inspector_screenshot.png
rename to site/web/assets/images/docs/tools/devtools/inspector_screenshot.png
diff --git a/src/content/assets/images/docs/tools/devtools/invert_oversized_images_icon.png b/site/web/assets/images/docs/tools/devtools/invert_oversized_images_icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/invert_oversized_images_icon.png
rename to site/web/assets/images/docs/tools/devtools/invert_oversized_images_icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/layout_explorer_cross_axis_alignment.webp b/site/web/assets/images/docs/tools/devtools/layout_explorer_cross_axis_alignment.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/layout_explorer_cross_axis_alignment.webp
rename to site/web/assets/images/docs/tools/devtools/layout_explorer_cross_axis_alignment.webp
diff --git a/src/content/assets/images/docs/tools/devtools/layout_explorer_errors_and_device.webp b/site/web/assets/images/docs/tools/devtools/layout_explorer_errors_and_device.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/layout_explorer_errors_and_device.webp
rename to site/web/assets/images/docs/tools/devtools/layout_explorer_errors_and_device.webp
diff --git a/src/content/assets/images/docs/tools/devtools/layout_explorer_fit.webp b/site/web/assets/images/docs/tools/devtools/layout_explorer_fit.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/layout_explorer_fit.webp
rename to site/web/assets/images/docs/tools/devtools/layout_explorer_fit.webp
diff --git a/src/content/assets/images/docs/tools/devtools/layout_explorer_fixed_layout.png b/site/web/assets/images/docs/tools/devtools/layout_explorer_fixed_layout.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/layout_explorer_fixed_layout.png
rename to site/web/assets/images/docs/tools/devtools/layout_explorer_fixed_layout.png
diff --git a/src/content/assets/images/docs/tools/devtools/layout_explorer_flex.webp b/site/web/assets/images/docs/tools/devtools/layout_explorer_flex.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/layout_explorer_flex.webp
rename to site/web/assets/images/docs/tools/devtools/layout_explorer_flex.webp
diff --git a/src/content/assets/images/docs/tools/devtools/layout_explorer_main_axis_alignment.webp b/site/web/assets/images/docs/tools/devtools/layout_explorer_main_axis_alignment.webp
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/layout_explorer_main_axis_alignment.webp
rename to site/web/assets/images/docs/tools/devtools/layout_explorer_main_axis_alignment.webp
diff --git a/src/content/assets/images/docs/tools/devtools/logging_log_entries.png b/site/web/assets/images/docs/tools/devtools/logging_log_entries.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/logging_log_entries.png
rename to site/web/assets/images/docs/tools/devtools/logging_log_entries.png
diff --git a/src/content/assets/images/docs/tools/devtools/memory_chart_anatomy.png b/site/web/assets/images/docs/tools/devtools/memory_chart_anatomy.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/memory_chart_anatomy.png
rename to site/web/assets/images/docs/tools/devtools/memory_chart_anatomy.png
diff --git a/src/content/assets/images/docs/tools/devtools/method-table.png b/site/web/assets/images/docs/tools/devtools/method-table.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/method-table.png
rename to site/web/assets/images/docs/tools/devtools/method-table.png
diff --git a/src/content/assets/images/docs/tools/devtools/more-debugging-options.png b/site/web/assets/images/docs/tools/devtools/more-debugging-options.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/more-debugging-options.png
rename to site/web/assets/images/docs/tools/devtools/more-debugging-options.png
diff --git a/src/content/assets/images/docs/tools/devtools/network_filter_dialog.png b/site/web/assets/images/docs/tools/devtools/network_filter_dialog.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/network_filter_dialog.png
rename to site/web/assets/images/docs/tools/devtools/network_filter_dialog.png
diff --git a/src/content/assets/images/docs/tools/devtools/network_screenshot.png b/site/web/assets/images/docs/tools/devtools/network_screenshot.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/network_screenshot.png
rename to site/web/assets/images/docs/tools/devtools/network_screenshot.png
diff --git a/src/content/assets/images/docs/tools/devtools/network_search_and_filter.png b/site/web/assets/images/docs/tools/devtools/network_search_and_filter.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/network_search_and_filter.png
rename to site/web/assets/images/docs/tools/devtools/network_search_and_filter.png
diff --git a/src/content/assets/images/docs/tools/devtools/network_startup_resume.png b/site/web/assets/images/docs/tools/devtools/network_startup_resume.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/network_startup_resume.png
rename to site/web/assets/images/docs/tools/devtools/network_startup_resume.png
diff --git a/src/content/assets/images/docs/tools/devtools/paint-baselines-icon.png b/site/web/assets/images/docs/tools/devtools/paint-baselines-icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/paint-baselines-icon.png
rename to site/web/assets/images/docs/tools/devtools/paint-baselines-icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/performance-overlay-green.png b/site/web/assets/images/docs/tools/devtools/performance-overlay-green.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/performance-overlay-green.png
rename to site/web/assets/images/docs/tools/devtools/performance-overlay-green.png
diff --git a/src/content/assets/images/docs/tools/devtools/performance-overlay-jank.png b/site/web/assets/images/docs/tools/devtools/performance-overlay-jank.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/performance-overlay-jank.png
rename to site/web/assets/images/docs/tools/devtools/performance-overlay-jank.png
diff --git a/src/content/assets/images/docs/tools/devtools/profile-tab.png b/site/web/assets/images/docs/tools/devtools/profile-tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/profile-tab.png
rename to site/web/assets/images/docs/tools/devtools/profile-tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-android-studio.png b/site/web/assets/images/docs/tools/devtools/property-editor-android-studio.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-android-studio.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-android-studio.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-documentation.gif b/site/web/assets/images/docs/tools/devtools/property-editor-documentation.gif
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-documentation.gif
rename to site/web/assets/images/docs/tools/devtools/property-editor-documentation.gif
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-filter-clear-button.png b/site/web/assets/images/docs/tools/devtools/property-editor-filter-clear-button.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-filter-clear-button.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-filter-clear-button.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-filter-menu-button.png b/site/web/assets/images/docs/tools/devtools/property-editor-filter-menu-button.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-filter-menu-button.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-filter-menu-button.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-filter-regex-toggle.png b/site/web/assets/images/docs/tools/devtools/property-editor-filter-regex-toggle.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-filter-regex-toggle.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-filter-regex-toggle.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-filter-text.png b/site/web/assets/images/docs/tools/devtools/property-editor-filter-text.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-filter-text.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-filter-text.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-icon-android-studio.png b/site/web/assets/images/docs/tools/devtools/property-editor-icon-android-studio.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-icon-android-studio.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-icon-android-studio.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-icon-vscode.png b/site/web/assets/images/docs/tools/devtools/property-editor-icon-vscode.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-icon-vscode.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-icon-vscode.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-labels.png b/site/web/assets/images/docs/tools/devtools/property-editor-labels.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-labels.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-labels.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-name-type.png b/site/web/assets/images/docs/tools/devtools/property-editor-name-type.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-name-type.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-name-type.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-text-widget.png b/site/web/assets/images/docs/tools/devtools/property-editor-text-widget.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-text-widget.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-text-widget.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-tooltip.png b/site/web/assets/images/docs/tools/devtools/property-editor-tooltip.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-tooltip.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-tooltip.png
diff --git a/src/content/assets/images/docs/tools/devtools/property-editor-vscode.png b/site/web/assets/images/docs/tools/devtools/property-editor-vscode.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/property-editor-vscode.png
rename to site/web/assets/images/docs/tools/devtools/property-editor-vscode.png
diff --git a/src/content/assets/images/docs/tools/devtools/refresh-tree-icon.png b/site/web/assets/images/docs/tools/devtools/refresh-tree-icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/refresh-tree-icon.png
rename to site/web/assets/images/docs/tools/devtools/refresh-tree-icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.10.0/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.10.0/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.10.0/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.10.0/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image2.gif b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image2.gif
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image2.gif
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image2.gif
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.12.1/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.12.1/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.12.1/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.12.1/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image2.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image2.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image2.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image2.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image2.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image2.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image2.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image2.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image3.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image3.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image3.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image3.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image2.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image2.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image2.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image2.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.17.0/frame_analysis.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.17.0/frame_analysis.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.17.0/frame_analysis.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.17.0/frame_analysis.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.17.0/package_directories.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.17.0/package_directories.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.17.0/package_directories.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.17.0/package_directories.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.18.0/allocation-tracing.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.18.0/allocation-tracing.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.18.0/allocation-tracing.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.18.0/allocation-tracing.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.18.0/profile.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.18.0/profile.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.18.0/profile.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.18.0/profile.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.18.0/render-time-column.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.18.0/render-time-column.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.18.0/render-time-column.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.18.0/render-time-column.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.19.0/4577.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.19.0/4577.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.19.0/4577.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.19.0/4577.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4693.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4693.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4693.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4693.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4700.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4700.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4700.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4700.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4714.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4714.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4714.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4714.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4722.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4722.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4722.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4722.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4803.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4803.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4803.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4803.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.21.1/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.21.1/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.21.1/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.21.1/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5181.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5181.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5181.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5181.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5201.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5201.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5201.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5201.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5248.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5248.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5248.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5248.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5290.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5290.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5290.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5290.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5320.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5320.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5320.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5320.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5323.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5323.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5323.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5323.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.23.1/cpu-method-table.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.23.1/cpu-method-table.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.23.1/cpu-method-table.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.23.1/cpu-method-table.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.23.1/verbose-logging.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.23.1/verbose-logging.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.23.1/verbose-logging.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.23.1/verbose-logging.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.25.0/memory.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.25.0/memory.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.25.0/memory.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.25.0/memory.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.26.1/home_screen.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.26.1/home_screen.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.26.1/home_screen.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.26.1/home_screen.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.27.0/truncation.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.27.0/truncation.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.27.0/truncation.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.27.0/truncation.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.28.1/example_devtools_extension.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.28.1/example_devtools_extension.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.28.1/example_devtools_extension.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.28.1/example_devtools_extension.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.28.1/logger_copy.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.28.1/logger_copy.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.28.1/logger_copy.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.28.1/logger_copy.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.28.3/watch_tutorial_link.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.28.3/watch_tutorial_link.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.28.3/watch_tutorial_link.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.28.3/watch_tutorial_link.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.29.0/open_file_performance_screen.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.29.0/open_file_performance_screen.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.29.0/open_file_performance_screen.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.29.0/open_file_performance_screen.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.29.0/track_platform_channels.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.29.0/track_platform_channels.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.29.0/track_platform_channels.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.29.0/track_platform_channels.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.30.0/flutter_frames_engine_text.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.30.0/flutter_frames_engine_text.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.30.0/flutter_frames_engine_text.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.30.0/flutter_frames_engine_text.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.31.0/hover-for-dropdown.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.31.0/hover-for-dropdown.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.31.0/hover-for-dropdown.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.31.0/hover-for-dropdown.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.31.0/link-to-doc.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.31.0/link-to-doc.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.31.0/link-to-doc.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.31.0/link-to-doc.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.32.0/logging_toggle_filters.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.32.0/logging_toggle_filters.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.32.0/logging_toggle_filters.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.32.0/logging_toggle_filters.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7197-export.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7197-export.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7197-export.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7197-export.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7369-timeline-settings.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7369-timeline-settings.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7369-timeline-settings.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7369-timeline-settings.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7463-overlay.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7463-overlay.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7463-overlay.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7463-overlay.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.35.0/json_viewer_copy.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.35.0/json_viewer_copy.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.35.0/json_viewer_copy.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.35.0/json_viewer_copy.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.35.0/network_recording.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.35.0/network_recording.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.35.0/network_recording.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.35.0/network_recording.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.35.0/profiler_recording.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.35.0/profiler_recording.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.35.0/profiler_recording.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.35.0/profiler_recording.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_counts_frame_analysis.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_counts_frame_analysis.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_counts_frame_analysis.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_counts_frame_analysis.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_stats.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_stats.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_stats.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_stats.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.36.0/track_build_counts_setting.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.36.0/track_build_counts_setting.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.36.0/track_build_counts_setting.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.36.0/track_build_counts_setting.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.37.2/devtools_in_sidebar.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.37.2/devtools_in_sidebar.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.37.2/devtools_in_sidebar.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.37.2/devtools_in_sidebar.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.37.2/socket-profiling.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.37.2/socket-profiling.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.37.2/socket-profiling.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.37.2/socket-profiling.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.40.2/deep_link_ios.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.40.2/deep_link_ios.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.40.2/deep_link_ios.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.40.2/deep_link_ios.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.40.2/new_inspector.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.40.2/new_inspector.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.40.2/new_inspector.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.40.2/new_inspector.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.40.2/wasm_setting.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.40.2/wasm_setting.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.40.2/wasm_setting.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.40.2/wasm_setting.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_filter.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_filter.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_filter.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_filter.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_level_filter.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_level_filter.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_level_filter.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_level_filter.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_metadata.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_metadata.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_metadata.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_metadata.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.41.0/network_filter.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.41.0/network_filter.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.41.0/network_filter.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.41.0/network_filter.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.42.3/inspector_auto_refresh_setting.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.42.3/inspector_auto_refresh_setting.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.42.3/inspector_auto_refresh_setting.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.42.3/inspector_auto_refresh_setting.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.42.3/legacy_inspector_setting.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.42.3/legacy_inspector_setting.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.42.3/legacy_inspector_setting.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.42.3/legacy_inspector_setting.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_controls.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_controls.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_controls.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_controls.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_open_save_button.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_open_save_button.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_open_save_button.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_open_save_button.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image1.gif b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image1.gif
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image1.gif
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image1.gif
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image2.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image2.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image2.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image2.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image3.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image3.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image3.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image3.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image4.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image4.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image4.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image4.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image5.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image5.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image5.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image5.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image6.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image6.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image6.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image6.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image2.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image2.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image2.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image2.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image3.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image3.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image3.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image3.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image4.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image4.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image4.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image4.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image5.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image5.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image5.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image5.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image2.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image2.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image2.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image2.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image3.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image3.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image3.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image3.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image1.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image1.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image1.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image1.png
diff --git a/src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image2.png b/site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image2.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image2.png
rename to site/web/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image2.png
diff --git a/src/content/assets/images/docs/tools/devtools/render-object-tab.png b/site/web/assets/images/docs/tools/devtools/render-object-tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/render-object-tab.png
rename to site/web/assets/images/docs/tools/devtools/render-object-tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/repaint-rainbow-icon.png b/site/web/assets/images/docs/tools/devtools/repaint-rainbow-icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/repaint-rainbow-icon.png
rename to site/web/assets/images/docs/tools/devtools/repaint-rainbow-icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/select-widget-mode-button.png b/site/web/assets/images/docs/tools/devtools/select-widget-mode-button.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/select-widget-mode-button.png
rename to site/web/assets/images/docs/tools/devtools/select-widget-mode-button.png
diff --git a/src/content/assets/images/docs/tools/devtools/select-widget-mode-icon.png b/site/web/assets/images/docs/tools/devtools/select-widget-mode-icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/select-widget-mode-icon.png
rename to site/web/assets/images/docs/tools/devtools/select-widget-mode-icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/shader-compilation-frames-chart.png b/site/web/assets/images/docs/tools/devtools/shader-compilation-frames-chart.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/shader-compilation-frames-chart.png
rename to site/web/assets/images/docs/tools/devtools/shader-compilation-frames-chart.png
diff --git a/src/content/assets/images/docs/tools/devtools/show-implementation-widgets-button.png b/site/web/assets/images/docs/tools/devtools/show-implementation-widgets-button.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/show-implementation-widgets-button.png
rename to site/web/assets/images/docs/tools/devtools/show-implementation-widgets-button.png
diff --git a/src/content/assets/images/docs/tools/devtools/slow-animations-icon.png b/site/web/assets/images/docs/tools/devtools/slow-animations-icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/slow-animations-icon.png
rename to site/web/assets/images/docs/tools/devtools/slow-animations-icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/table-element.png b/site/web/assets/images/docs/tools/devtools/table-element.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/table-element.png
rename to site/web/assets/images/docs/tools/devtools/table-element.png
diff --git a/src/content/assets/images/docs/tools/devtools/timeline-events-tab.png b/site/web/assets/images/docs/tools/devtools/timeline-events-tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/timeline-events-tab.png
rename to site/web/assets/images/docs/tools/devtools/timeline-events-tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/toggle-platform-icon.png b/site/web/assets/images/docs/tools/devtools/toggle-platform-icon.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/toggle-platform-icon.png
rename to site/web/assets/images/docs/tools/devtools/toggle-platform-icon.png
diff --git a/src/content/assets/images/docs/tools/devtools/trace-instances-tab.png b/site/web/assets/images/docs/tools/devtools/trace-instances-tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/trace-instances-tab.png
rename to site/web/assets/images/docs/tools/devtools/trace-instances-tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/trace-view.png b/site/web/assets/images/docs/tools/devtools/trace-view.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/trace-view.png
rename to site/web/assets/images/docs/tools/devtools/trace-view.png
diff --git a/src/content/assets/images/docs/tools/devtools/track-layouts.png b/site/web/assets/images/docs/tools/devtools/track-layouts.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/track-layouts.png
rename to site/web/assets/images/docs/tools/devtools/track-layouts.png
diff --git a/src/content/assets/images/docs/tools/devtools/track-paints.png b/site/web/assets/images/docs/tools/devtools/track-paints.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/track-paints.png
rename to site/web/assets/images/docs/tools/devtools/track-paints.png
diff --git a/src/content/assets/images/docs/tools/devtools/track-widget-builds.png b/site/web/assets/images/docs/tools/devtools/track-widget-builds.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/track-widget-builds.png
rename to site/web/assets/images/docs/tools/devtools/track-widget-builds.png
diff --git a/src/content/assets/images/docs/tools/devtools/track_widget_creation_disabled.png b/site/web/assets/images/docs/tools/devtools/track_widget_creation_disabled.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/track_widget_creation_disabled.png
rename to site/web/assets/images/docs/tools/devtools/track_widget_creation_disabled.png
diff --git a/src/content/assets/images/docs/tools/devtools/track_widget_creation_enabled.png b/site/web/assets/images/docs/tools/devtools/track_widget_creation_enabled.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/track_widget_creation_enabled.png
rename to site/web/assets/images/docs/tools/devtools/track_widget_creation_enabled.png
diff --git a/src/content/assets/images/docs/tools/devtools/treemap_breadcrumbs.png b/site/web/assets/images/docs/tools/devtools/treemap_breadcrumbs.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/treemap_breadcrumbs.png
rename to site/web/assets/images/docs/tools/devtools/treemap_breadcrumbs.png
diff --git a/src/content/assets/images/docs/tools/devtools/visual_debugging_options.png b/site/web/assets/images/docs/tools/devtools/visual_debugging_options.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/visual_debugging_options.png
rename to site/web/assets/images/docs/tools/devtools/visual_debugging_options.png
diff --git a/src/content/assets/images/docs/tools/devtools/widget-properties-tab.png b/site/web/assets/images/docs/tools/devtools/widget-properties-tab.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/widget-properties-tab.png
rename to site/web/assets/images/docs/tools/devtools/widget-properties-tab.png
diff --git a/src/content/assets/images/docs/tools/devtools/widget-tree-with-implementation-widgets.png b/site/web/assets/images/docs/tools/devtools/widget-tree-with-implementation-widgets.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/widget-tree-with-implementation-widgets.png
rename to site/web/assets/images/docs/tools/devtools/widget-tree-with-implementation-widgets.png
diff --git a/src/content/assets/images/docs/tools/devtools/widget-tree.png b/site/web/assets/images/docs/tools/devtools/widget-tree.png
similarity index 100%
rename from src/content/assets/images/docs/tools/devtools/widget-tree.png
rename to site/web/assets/images/docs/tools/devtools/widget-tree.png
diff --git a/src/content/assets/images/docs/tools/hot-reload.gif b/site/web/assets/images/docs/tools/hot-reload.gif
similarity index 100%
rename from src/content/assets/images/docs/tools/hot-reload.gif
rename to site/web/assets/images/docs/tools/hot-reload.gif
diff --git a/src/content/assets/images/docs/tools/vs-code/assists.png b/site/web/assets/images/docs/tools/vs-code/assists.png
similarity index 100%
rename from src/content/assets/images/docs/tools/vs-code/assists.png
rename to site/web/assets/images/docs/tools/vs-code/assists.png
diff --git a/src/content/assets/images/docs/tools/vs-code/debug_console.png b/site/web/assets/images/docs/tools/vs-code/debug_console.png
similarity index 100%
rename from src/content/assets/images/docs/tools/vs-code/debug_console.png
rename to site/web/assets/images/docs/tools/vs-code/debug_console.png
diff --git a/src/content/assets/images/docs/tools/vs-code/device_status_bar.png b/site/web/assets/images/docs/tools/vs-code/device_status_bar.png
similarity index 100%
rename from src/content/assets/images/docs/tools/vs-code/device_status_bar.png
rename to site/web/assets/images/docs/tools/vs-code/device_status_bar.png
diff --git a/src/content/assets/images/docs/tools/vs-code/problems.png b/site/web/assets/images/docs/tools/vs-code/problems.png
similarity index 100%
rename from src/content/assets/images/docs/tools/vs-code/problems.png
rename to site/web/assets/images/docs/tools/vs-code/problems.png
diff --git a/src/content/assets/images/docs/tools/vs-code/snippets.png b/site/web/assets/images/docs/tools/vs-code/snippets.png
similarity index 100%
rename from src/content/assets/images/docs/tools/vs-code/snippets.png
rename to site/web/assets/images/docs/tools/vs-code/snippets.png
diff --git a/src/content/assets/images/docs/tools/vs-code/vscode_command.png b/site/web/assets/images/docs/tools/vs-code/vscode_command.png
similarity index 100%
rename from src/content/assets/images/docs/tools/vs-code/vscode_command.png
rename to site/web/assets/images/docs/tools/vs-code/vscode_command.png
diff --git a/src/content/assets/images/docs/tools/vs-code/vscode_embedded.png b/site/web/assets/images/docs/tools/vs-code/vscode_embedded.png
similarity index 100%
rename from src/content/assets/images/docs/tools/vs-code/vscode_embedded.png
rename to site/web/assets/images/docs/tools/vs-code/vscode_embedded.png
diff --git a/src/content/assets/images/docs/tools/vs-code/vscode_status_bar.png b/site/web/assets/images/docs/tools/vs-code/vscode_status_bar.png
similarity index 100%
rename from src/content/assets/images/docs/tools/vs-code/vscode_status_bar.png
rename to site/web/assets/images/docs/tools/vs-code/vscode_status_bar.png
diff --git a/src/content/assets/images/docs/tools/widget-previewer/widget-previewer.png b/site/web/assets/images/docs/tools/widget-previewer/widget-previewer.png
similarity index 100%
rename from src/content/assets/images/docs/tools/widget-previewer/widget-previewer.png
rename to site/web/assets/images/docs/tools/widget-previewer/widget-previewer.png
diff --git a/src/content/assets/images/docs/tutorial/app_with_input.png b/site/web/assets/images/docs/tutorial/app_with_input.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/app_with_input.png
rename to site/web/assets/images/docs/tutorial/app_with_input.png
diff --git a/src/content/assets/images/docs/tutorial/appbar.png b/site/web/assets/images/docs/tutorial/appbar.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/appbar.png
rename to site/web/assets/images/docs/tutorial/appbar.png
diff --git a/src/content/assets/images/docs/tutorial/birdle.png b/site/web/assets/images/docs/tutorial/birdle.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/birdle.png
rename to site/web/assets/images/docs/tutorial/birdle.png
diff --git a/src/content/assets/images/docs/tutorial/grid_of_tiles.png b/site/web/assets/images/docs/tutorial/grid_of_tiles.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/grid_of_tiles.png
rename to site/web/assets/images/docs/tutorial/grid_of_tiles.png
diff --git a/src/content/assets/images/docs/tutorial/hello_world.png b/site/web/assets/images/docs/tutorial/hello_world.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/hello_world.png
rename to site/web/assets/images/docs/tutorial/hello_world.png
diff --git a/src/content/assets/images/docs/tutorial/initial_widget_tree.png b/site/web/assets/images/docs/tutorial/initial_widget_tree.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/initial_widget_tree.png
rename to site/web/assets/images/docs/tutorial/initial_widget_tree.png
diff --git a/src/content/assets/images/docs/tutorial/property_editor.png b/site/web/assets/images/docs/tutorial/property_editor.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/property_editor.png
rename to site/web/assets/images/docs/tutorial/property_editor.png
diff --git a/src/content/assets/images/docs/tutorial/tiles.png b/site/web/assets/images/docs/tutorial/tiles.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/tiles.png
rename to site/web/assets/images/docs/tutorial/tiles.png
diff --git a/src/content/assets/images/docs/tutorial/widget_inspector.png b/site/web/assets/images/docs/tutorial/widget_inspector.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/widget_inspector.png
rename to site/web/assets/images/docs/tutorial/widget_inspector.png
diff --git a/src/content/assets/images/docs/tutorial/widget_tree_rows_columns.png b/site/web/assets/images/docs/tutorial/widget_tree_rows_columns.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/widget_tree_rows_columns.png
rename to site/web/assets/images/docs/tutorial/widget_tree_rows_columns.png
diff --git a/src/content/assets/images/docs/tutorial/widget_tree_stateful.png b/site/web/assets/images/docs/tutorial/widget_tree_stateful.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/widget_tree_stateful.png
rename to site/web/assets/images/docs/tutorial/widget_tree_stateful.png
diff --git a/src/content/assets/images/docs/tutorial/widget_tree_with_app_bar.png b/site/web/assets/images/docs/tutorial/widget_tree_with_app_bar.png
similarity index 100%
rename from src/content/assets/images/docs/tutorial/widget_tree_with_app_bar.png
rename to site/web/assets/images/docs/tutorial/widget_tree_with_app_bar.png
diff --git a/src/content/assets/images/docs/ui/AnimatedBuilder-WidgetTree.png b/site/web/assets/images/docs/ui/AnimatedBuilder-WidgetTree.png
similarity index 100%
rename from src/content/assets/images/docs/ui/AnimatedBuilder-WidgetTree.png
rename to site/web/assets/images/docs/ui/AnimatedBuilder-WidgetTree.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/abstract.png b/site/web/assets/images/docs/ui/adaptive-responsive/abstract.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/abstract.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/abstract.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/adaptive_scaffold.webp b/site/web/assets/images/docs/ui/adaptive-responsive/adaptive_scaffold.webp
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/adaptive_scaffold.webp
rename to site/web/assets/images/docs/ui/adaptive-responsive/adaptive_scaffold.webp
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/adaptive_scaffold2.webp b/site/web/assets/images/docs/ui/adaptive-responsive/adaptive_scaffold2.webp
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/adaptive_scaffold2.webp
rename to site/web/assets/images/docs/ui/adaptive-responsive/adaptive_scaffold2.webp
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/branch.png b/site/web/assets/images/docs/ui/adaptive-responsive/branch.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/branch.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/branch.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/embed_image1.png b/site/web/assets/images/docs/ui/adaptive-responsive/embed_image1.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/embed_image1.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/embed_image1.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/embed_image2.png b/site/web/assets/images/docs/ui/adaptive-responsive/embed_image2.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/embed_image2.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/embed_image2.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/large-screen-guidelines.png b/site/web/assets/images/docs/ui/adaptive-responsive/large-screen-guidelines.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/large-screen-guidelines.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/large-screen-guidelines.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/large-screen.png b/site/web/assets/images/docs/ui/adaptive-responsive/large-screen.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/large-screen.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/large-screen.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/measure.png b/site/web/assets/images/docs/ui/adaptive-responsive/measure.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/measure.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/measure.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/platforms.png b/site/web/assets/images/docs/ui/adaptive-responsive/platforms.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/platforms.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/platforms.png
diff --git a/src/content/assets/images/docs/ui/adaptive-responsive/titlebar.png b/site/web/assets/images/docs/ui/adaptive-responsive/titlebar.png
similarity index 100%
rename from src/content/assets/images/docs/ui/adaptive-responsive/titlebar.png
rename to site/web/assets/images/docs/ui/adaptive-responsive/titlebar.png
diff --git a/src/content/assets/images/docs/ui/animations/StaggeredAnimationIntervals.png b/site/web/assets/images/docs/ui/animations/StaggeredAnimationIntervals.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/StaggeredAnimationIntervals.png
rename to site/web/assets/images/docs/ui/animations/StaggeredAnimationIntervals.png
diff --git a/src/content/assets/images/docs/ui/animations/animation-decision-tree.png b/site/web/assets/images/docs/ui/animations/animation-decision-tree.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/animation-decision-tree.png
rename to site/web/assets/images/docs/ui/animations/animation-decision-tree.png
diff --git a/src/content/assets/images/docs/ui/animations/hero-transition-0.png b/site/web/assets/images/docs/ui/animations/hero-transition-0.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/hero-transition-0.png
rename to site/web/assets/images/docs/ui/animations/hero-transition-0.png
diff --git a/src/content/assets/images/docs/ui/animations/hero-transition-1.png b/site/web/assets/images/docs/ui/animations/hero-transition-1.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/hero-transition-1.png
rename to site/web/assets/images/docs/ui/animations/hero-transition-1.png
diff --git a/src/content/assets/images/docs/ui/animations/hero-transition-2.png b/site/web/assets/images/docs/ui/animations/hero-transition-2.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/hero-transition-2.png
rename to site/web/assets/images/docs/ui/animations/hero-transition-2.png
diff --git a/src/content/assets/images/docs/ui/animations/hero-transition-3.png b/site/web/assets/images/docs/ui/animations/hero-transition-3.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/hero-transition-3.png
rename to site/web/assets/images/docs/ui/animations/hero-transition-3.png
diff --git a/src/content/assets/images/docs/ui/animations/photohero-class.png b/site/web/assets/images/docs/ui/animations/photohero-class.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/photohero-class.png
rename to site/web/assets/images/docs/ui/animations/photohero-class.png
diff --git a/src/content/assets/images/docs/ui/animations/radial-expansion-class.png b/site/web/assets/images/docs/ui/animations/radial-expansion-class.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/radial-expansion-class.png
rename to site/web/assets/images/docs/ui/animations/radial-expansion-class.png
diff --git a/src/content/assets/images/docs/ui/animations/radial-hero-animation.png b/site/web/assets/images/docs/ui/animations/radial-hero-animation.png
similarity index 100%
rename from src/content/assets/images/docs/ui/animations/radial-hero-animation.png
rename to site/web/assets/images/docs/ui/animations/radial-hero-animation.png
diff --git a/src/content/assets/images/docs/ui/favorited-not-favorited.png b/site/web/assets/images/docs/ui/favorited-not-favorited.png
similarity index 100%
rename from src/content/assets/images/docs/ui/favorited-not-favorited.png
rename to site/web/assets/images/docs/ui/favorited-not-favorited.png
diff --git a/src/content/assets/images/docs/ui/layout/article-hero-image.png b/site/web/assets/images/docs/ui/layout/article-hero-image.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/article-hero-image.png
rename to site/web/assets/images/docs/ui/layout/article-hero-image.png
diff --git a/src/content/assets/images/docs/ui/layout/button-section-diagram.png b/site/web/assets/images/docs/ui/layout/button-section-diagram.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/button-section-diagram.png
rename to site/web/assets/images/docs/ui/layout/button-section-diagram.png
diff --git a/src/content/assets/images/docs/ui/layout/card-flutter-gallery.png b/site/web/assets/images/docs/ui/layout/card-flutter-gallery.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/card-flutter-gallery.png
rename to site/web/assets/images/docs/ui/layout/card-flutter-gallery.png
diff --git a/src/content/assets/images/docs/ui/layout/card.png b/site/web/assets/images/docs/ui/layout/card.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/card.png
rename to site/web/assets/images/docs/ui/layout/card.png
diff --git a/src/content/assets/images/docs/ui/layout/children.png b/site/web/assets/images/docs/ui/layout/children.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/children.png
rename to site/web/assets/images/docs/ui/layout/children.png
diff --git a/src/content/assets/images/docs/ui/layout/column-diagram.png b/site/web/assets/images/docs/ui/layout/column-diagram.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/column-diagram.png
rename to site/web/assets/images/docs/ui/layout/column-diagram.png
diff --git a/src/content/assets/images/docs/ui/layout/column-visual.png b/site/web/assets/images/docs/ui/layout/column-visual.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/column-visual.png
rename to site/web/assets/images/docs/ui/layout/column-visual.png
diff --git a/src/content/assets/images/docs/ui/layout/container.png b/site/web/assets/images/docs/ui/layout/container.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/container.png
rename to site/web/assets/images/docs/ui/layout/container.png
diff --git a/src/content/assets/images/docs/ui/layout/gridview-count-flutter-gallery.png b/site/web/assets/images/docs/ui/layout/gridview-count-flutter-gallery.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/gridview-count-flutter-gallery.png
rename to site/web/assets/images/docs/ui/layout/gridview-count-flutter-gallery.png
diff --git a/src/content/assets/images/docs/ui/layout/gridview-extent.png b/site/web/assets/images/docs/ui/layout/gridview-extent.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/gridview-extent.png
rename to site/web/assets/images/docs/ui/layout/gridview-extent.png
diff --git a/src/content/assets/images/docs/ui/layout/hello-world.png b/site/web/assets/images/docs/ui/layout/hello-world.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/hello-world.png
rename to site/web/assets/images/docs/ui/layout/hello-world.png
diff --git a/src/content/assets/images/docs/ui/layout/lakes-column-elts.png b/site/web/assets/images/docs/ui/layout/lakes-column-elts.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/lakes-column-elts.png
rename to site/web/assets/images/docs/ui/layout/lakes-column-elts.png
diff --git a/src/content/assets/images/docs/ui/layout/lakes-icons-visual.png b/site/web/assets/images/docs/ui/layout/lakes-icons-visual.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/lakes-icons-visual.png
rename to site/web/assets/images/docs/ui/layout/lakes-icons-visual.png
diff --git a/src/content/assets/images/docs/ui/layout/lakes-icons.png b/site/web/assets/images/docs/ui/layout/lakes-icons.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/lakes-icons.png
rename to site/web/assets/images/docs/ui/layout/lakes-icons.png
diff --git a/src/content/assets/images/docs/ui/layout/lakes.jpg b/site/web/assets/images/docs/ui/layout/lakes.jpg
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/lakes.jpg
rename to site/web/assets/images/docs/ui/layout/lakes.jpg
diff --git a/src/content/assets/images/docs/ui/layout/layout-1.png b/site/web/assets/images/docs/ui/layout/layout-1.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-1.png
rename to site/web/assets/images/docs/ui/layout/layout-1.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-10.png b/site/web/assets/images/docs/ui/layout/layout-10.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-10.png
rename to site/web/assets/images/docs/ui/layout/layout-10.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-11.png b/site/web/assets/images/docs/ui/layout/layout-11.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-11.png
rename to site/web/assets/images/docs/ui/layout/layout-11.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-12.png b/site/web/assets/images/docs/ui/layout/layout-12.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-12.png
rename to site/web/assets/images/docs/ui/layout/layout-12.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-13.png b/site/web/assets/images/docs/ui/layout/layout-13.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-13.png
rename to site/web/assets/images/docs/ui/layout/layout-13.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-14.png b/site/web/assets/images/docs/ui/layout/layout-14.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-14.png
rename to site/web/assets/images/docs/ui/layout/layout-14.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-15.png b/site/web/assets/images/docs/ui/layout/layout-15.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-15.png
rename to site/web/assets/images/docs/ui/layout/layout-15.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-16.png b/site/web/assets/images/docs/ui/layout/layout-16.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-16.png
rename to site/web/assets/images/docs/ui/layout/layout-16.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-17.png b/site/web/assets/images/docs/ui/layout/layout-17.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-17.png
rename to site/web/assets/images/docs/ui/layout/layout-17.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-18.png b/site/web/assets/images/docs/ui/layout/layout-18.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-18.png
rename to site/web/assets/images/docs/ui/layout/layout-18.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-19.png b/site/web/assets/images/docs/ui/layout/layout-19.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-19.png
rename to site/web/assets/images/docs/ui/layout/layout-19.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-2.png b/site/web/assets/images/docs/ui/layout/layout-2.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-2.png
rename to site/web/assets/images/docs/ui/layout/layout-2.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-20.png b/site/web/assets/images/docs/ui/layout/layout-20.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-20.png
rename to site/web/assets/images/docs/ui/layout/layout-20.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-21.png b/site/web/assets/images/docs/ui/layout/layout-21.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-21.png
rename to site/web/assets/images/docs/ui/layout/layout-21.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-22.png b/site/web/assets/images/docs/ui/layout/layout-22.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-22.png
rename to site/web/assets/images/docs/ui/layout/layout-22.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-23.png b/site/web/assets/images/docs/ui/layout/layout-23.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-23.png
rename to site/web/assets/images/docs/ui/layout/layout-23.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-24.png b/site/web/assets/images/docs/ui/layout/layout-24.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-24.png
rename to site/web/assets/images/docs/ui/layout/layout-24.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-25.png b/site/web/assets/images/docs/ui/layout/layout-25.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-25.png
rename to site/web/assets/images/docs/ui/layout/layout-25.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-26.png b/site/web/assets/images/docs/ui/layout/layout-26.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-26.png
rename to site/web/assets/images/docs/ui/layout/layout-26.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-27.png b/site/web/assets/images/docs/ui/layout/layout-27.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-27.png
rename to site/web/assets/images/docs/ui/layout/layout-27.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-28.png b/site/web/assets/images/docs/ui/layout/layout-28.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-28.png
rename to site/web/assets/images/docs/ui/layout/layout-28.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-29.png b/site/web/assets/images/docs/ui/layout/layout-29.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-29.png
rename to site/web/assets/images/docs/ui/layout/layout-29.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-3.png b/site/web/assets/images/docs/ui/layout/layout-3.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-3.png
rename to site/web/assets/images/docs/ui/layout/layout-3.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-4.png b/site/web/assets/images/docs/ui/layout/layout-4.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-4.png
rename to site/web/assets/images/docs/ui/layout/layout-4.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-5.png b/site/web/assets/images/docs/ui/layout/layout-5.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-5.png
rename to site/web/assets/images/docs/ui/layout/layout-5.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-6.png b/site/web/assets/images/docs/ui/layout/layout-6.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-6.png
rename to site/web/assets/images/docs/ui/layout/layout-6.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-7.png b/site/web/assets/images/docs/ui/layout/layout-7.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-7.png
rename to site/web/assets/images/docs/ui/layout/layout-7.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-8.png b/site/web/assets/images/docs/ui/layout/layout-8.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-8.png
rename to site/web/assets/images/docs/ui/layout/layout-8.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-9.png b/site/web/assets/images/docs/ui/layout/layout-9.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-9.png
rename to site/web/assets/images/docs/ui/layout/layout-9.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-demo-app.png b/site/web/assets/images/docs/ui/layout/layout-demo-app.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-demo-app.png
rename to site/web/assets/images/docs/ui/layout/layout-demo-app.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-final.png b/site/web/assets/images/docs/ui/layout/layout-final.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-final.png
rename to site/web/assets/images/docs/ui/layout/layout-final.png
diff --git a/src/content/assets/images/docs/ui/layout/layout-sketch-add-text-block.svg b/site/web/assets/images/docs/ui/layout/layout-sketch-add-text-block.svg
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-sketch-add-text-block.svg
rename to site/web/assets/images/docs/ui/layout/layout-sketch-add-text-block.svg
diff --git a/src/content/assets/images/docs/ui/layout/layout-sketch-button-block-unlabeled.svg b/site/web/assets/images/docs/ui/layout/layout-sketch-button-block-unlabeled.svg
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-sketch-button-block-unlabeled.svg
rename to site/web/assets/images/docs/ui/layout/layout-sketch-button-block-unlabeled.svg
diff --git a/src/content/assets/images/docs/ui/layout/layout-sketch-button-block.svg b/site/web/assets/images/docs/ui/layout/layout-sketch-button-block.svg
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-sketch-button-block.svg
rename to site/web/assets/images/docs/ui/layout/layout-sketch-button-block.svg
diff --git a/src/content/assets/images/docs/ui/layout/layout-sketch-intro.svg b/site/web/assets/images/docs/ui/layout/layout-sketch-intro.svg
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-sketch-intro.svg
rename to site/web/assets/images/docs/ui/layout/layout-sketch-intro.svg
diff --git a/src/content/assets/images/docs/ui/layout/layout-sketch-title-block-unlabeled.svg b/site/web/assets/images/docs/ui/layout/layout-sketch-title-block-unlabeled.svg
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-sketch-title-block-unlabeled.svg
rename to site/web/assets/images/docs/ui/layout/layout-sketch-title-block-unlabeled.svg
diff --git a/src/content/assets/images/docs/ui/layout/layout-sketch-title-block.svg b/site/web/assets/images/docs/ui/layout/layout-sketch-title-block.svg
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-sketch-title-block.svg
rename to site/web/assets/images/docs/ui/layout/layout-sketch-title-block.svg
diff --git a/src/content/assets/images/docs/ui/layout/layout-sketch.svg b/site/web/assets/images/docs/ui/layout/layout-sketch.svg
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-sketch.svg
rename to site/web/assets/images/docs/ui/layout/layout-sketch.svg
diff --git a/src/content/assets/images/docs/ui/layout/layout-too-large.png b/site/web/assets/images/docs/ui/layout/layout-too-large.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/layout-too-large.png
rename to site/web/assets/images/docs/ui/layout/layout-too-large.png
diff --git a/src/content/assets/images/docs/ui/layout/listtile-flutter-gallery.png b/site/web/assets/images/docs/ui/layout/listtile-flutter-gallery.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/listtile-flutter-gallery.png
rename to site/web/assets/images/docs/ui/layout/listtile-flutter-gallery.png
diff --git a/src/content/assets/images/docs/ui/layout/listview-color-gallery.png b/site/web/assets/images/docs/ui/layout/listview-color-gallery.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/listview-color-gallery.png
rename to site/web/assets/images/docs/ui/layout/listview-color-gallery.png
diff --git a/src/content/assets/images/docs/ui/layout/listview.png b/site/web/assets/images/docs/ui/layout/listview.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/listview.png
rename to site/web/assets/images/docs/ui/layout/listview.png
diff --git a/src/content/assets/images/docs/ui/layout/margin-padding-border.png b/site/web/assets/images/docs/ui/layout/margin-padding-border.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/margin-padding-border.png
rename to site/web/assets/images/docs/ui/layout/margin-padding-border.png
diff --git a/src/content/assets/images/docs/ui/layout/packed.png b/site/web/assets/images/docs/ui/layout/packed.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/packed.png
rename to site/web/assets/images/docs/ui/layout/packed.png
diff --git a/src/content/assets/images/docs/ui/layout/pavlova-diagram.png b/site/web/assets/images/docs/ui/layout/pavlova-diagram.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/pavlova-diagram.png
rename to site/web/assets/images/docs/ui/layout/pavlova-diagram.png
diff --git a/src/content/assets/images/docs/ui/layout/pavlova-icons-row-diagram.png b/site/web/assets/images/docs/ui/layout/pavlova-icons-row-diagram.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/pavlova-icons-row-diagram.png
rename to site/web/assets/images/docs/ui/layout/pavlova-icons-row-diagram.png
diff --git a/src/content/assets/images/docs/ui/layout/pavlova-large-annotated.png b/site/web/assets/images/docs/ui/layout/pavlova-large-annotated.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/pavlova-large-annotated.png
rename to site/web/assets/images/docs/ui/layout/pavlova-large-annotated.png
diff --git a/src/content/assets/images/docs/ui/layout/pavlova-large.png b/site/web/assets/images/docs/ui/layout/pavlova-large.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/pavlova-large.png
rename to site/web/assets/images/docs/ui/layout/pavlova-large.png
diff --git a/src/content/assets/images/docs/ui/layout/pavlova-left-column-diagram.png b/site/web/assets/images/docs/ui/layout/pavlova-left-column-diagram.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/pavlova-left-column-diagram.png
rename to site/web/assets/images/docs/ui/layout/pavlova-left-column-diagram.png
diff --git a/src/content/assets/images/docs/ui/layout/pavlova-ratings-row-diagram.png b/site/web/assets/images/docs/ui/layout/pavlova-ratings-row-diagram.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/pavlova-ratings-row-diagram.png
rename to site/web/assets/images/docs/ui/layout/pavlova-ratings-row-diagram.png
diff --git a/src/content/assets/images/docs/ui/layout/pavlova-visual.png b/site/web/assets/images/docs/ui/layout/pavlova-visual.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/pavlova-visual.png
rename to site/web/assets/images/docs/ui/layout/pavlova-visual.png
diff --git a/src/content/assets/images/docs/ui/layout/pavlova.png b/site/web/assets/images/docs/ui/layout/pavlova.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/pavlova.png
rename to site/web/assets/images/docs/ui/layout/pavlova.png
diff --git a/src/content/assets/images/docs/ui/layout/row-diagram.png b/site/web/assets/images/docs/ui/layout/row-diagram.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/row-diagram.png
rename to site/web/assets/images/docs/ui/layout/row-diagram.png
diff --git a/src/content/assets/images/docs/ui/layout/row-expanded-2-visual.png b/site/web/assets/images/docs/ui/layout/row-expanded-2-visual.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/row-expanded-2-visual.png
rename to site/web/assets/images/docs/ui/layout/row-expanded-2-visual.png
diff --git a/src/content/assets/images/docs/ui/layout/row-expanded-visual.png b/site/web/assets/images/docs/ui/layout/row-expanded-visual.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/row-expanded-visual.png
rename to site/web/assets/images/docs/ui/layout/row-expanded-visual.png
diff --git a/src/content/assets/images/docs/ui/layout/row-spaceevenly-visual.png b/site/web/assets/images/docs/ui/layout/row-spaceevenly-visual.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/row-spaceevenly-visual.png
rename to site/web/assets/images/docs/ui/layout/row-spaceevenly-visual.png
diff --git a/src/content/assets/images/docs/ui/layout/sample-flutter-layout.png b/site/web/assets/images/docs/ui/layout/sample-flutter-layout.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/sample-flutter-layout.png
rename to site/web/assets/images/docs/ui/layout/sample-flutter-layout.png
diff --git a/src/content/assets/images/docs/ui/layout/stack-flutter-gallery.png b/site/web/assets/images/docs/ui/layout/stack-flutter-gallery.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/stack-flutter-gallery.png
rename to site/web/assets/images/docs/ui/layout/stack-flutter-gallery.png
diff --git a/src/content/assets/images/docs/ui/layout/stack.png b/site/web/assets/images/docs/ui/layout/stack.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/stack.png
rename to site/web/assets/images/docs/ui/layout/stack.png
diff --git a/src/content/assets/images/docs/ui/layout/title-section-parts.png b/site/web/assets/images/docs/ui/layout/title-section-parts.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/title-section-parts.png
rename to site/web/assets/images/docs/ui/layout/title-section-parts.png
diff --git a/src/content/assets/images/docs/ui/layout/widget-tree-pavlova-icon-row.png b/site/web/assets/images/docs/ui/layout/widget-tree-pavlova-icon-row.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/widget-tree-pavlova-icon-row.png
rename to site/web/assets/images/docs/ui/layout/widget-tree-pavlova-icon-row.png
diff --git a/src/content/assets/images/docs/ui/layout/widget-tree-pavlova-rating-row.png b/site/web/assets/images/docs/ui/layout/widget-tree-pavlova-rating-row.png
similarity index 100%
rename from src/content/assets/images/docs/ui/layout/widget-tree-pavlova-rating-row.png
rename to site/web/assets/images/docs/ui/layout/widget-tree-pavlova-rating-row.png
diff --git a/src/content/assets/images/docs/ui/tapbox-active-state.png b/site/web/assets/images/docs/ui/tapbox-active-state.png
similarity index 100%
rename from src/content/assets/images/docs/ui/tapbox-active-state.png
rename to site/web/assets/images/docs/ui/tapbox-active-state.png
diff --git a/src/content/assets/images/docs/ui/tapbox-inactive-state.png b/site/web/assets/images/docs/ui/tapbox-inactive-state.png
similarity index 100%
rename from src/content/assets/images/docs/ui/tapbox-inactive-state.png
rename to site/web/assets/images/docs/ui/tapbox-inactive-state.png
diff --git a/src/content/assets/images/docs/using_shortcuts.png b/site/web/assets/images/docs/using_shortcuts.png
similarity index 100%
rename from src/content/assets/images/docs/using_shortcuts.png
rename to site/web/assets/images/docs/using_shortcuts.png
diff --git a/src/content/assets/images/docs/verbose_flag.png b/site/web/assets/images/docs/verbose_flag.png
similarity index 100%
rename from src/content/assets/images/docs/verbose_flag.png
rename to site/web/assets/images/docs/verbose_flag.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoAdaptiveTextSelectionToolbar.png b/site/web/assets/images/docs/widget-catalog/CupertinoAdaptiveTextSelectionToolbar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoAdaptiveTextSelectionToolbar.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoAdaptiveTextSelectionToolbar.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoApp.png b/site/web/assets/images/docs/widget-catalog/CupertinoApp.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoApp.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoApp.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoCheckbox.png b/site/web/assets/images/docs/widget-catalog/CupertinoCheckbox.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoCheckbox.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoCheckbox.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoColors.png b/site/web/assets/images/docs/widget-catalog/CupertinoColors.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoColors.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoColors.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoContextMenuAction.png b/site/web/assets/images/docs/widget-catalog/CupertinoContextMenuAction.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoContextMenuAction.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoContextMenuAction.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoDatePicker.png b/site/web/assets/images/docs/widget-catalog/CupertinoDatePicker.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoDatePicker.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoDatePicker.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoDesktopTextSelectionToolbar.png b/site/web/assets/images/docs/widget-catalog/CupertinoDesktopTextSelectionToolbar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoDesktopTextSelectionToolbar.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoDesktopTextSelectionToolbar.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoDesktopTextSelectionToolbarButton.png b/site/web/assets/images/docs/widget-catalog/CupertinoDesktopTextSelectionToolbarButton.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoDesktopTextSelectionToolbarButton.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoDesktopTextSelectionToolbarButton.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoFormRow.png b/site/web/assets/images/docs/widget-catalog/CupertinoFormRow.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoFormRow.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoFormRow.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoFormSection.png b/site/web/assets/images/docs/widget-catalog/CupertinoFormSection.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoFormSection.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoFormSection.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoListTileChevron.png b/site/web/assets/images/docs/widget-catalog/CupertinoListTileChevron.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoListTileChevron.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoListTileChevron.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoNavigationBarBackButton.png b/site/web/assets/images/docs/widget-catalog/CupertinoNavigationBarBackButton.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoNavigationBarBackButton.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoNavigationBarBackButton.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoPicker.png b/site/web/assets/images/docs/widget-catalog/CupertinoPicker.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoPicker.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoPicker.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoRadio.png b/site/web/assets/images/docs/widget-catalog/CupertinoRadio.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoRadio.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoRadio.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoSpellCheckSuggestionsToolbar.png b/site/web/assets/images/docs/widget-catalog/CupertinoSpellCheckSuggestionsToolbar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoSpellCheckSuggestionsToolbar.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoSpellCheckSuggestionsToolbar.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoTextFormFieldRow.png b/site/web/assets/images/docs/widget-catalog/CupertinoTextFormFieldRow.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoTextFormFieldRow.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoTextFormFieldRow.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoTextMagnifier.png b/site/web/assets/images/docs/widget-catalog/CupertinoTextMagnifier.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoTextMagnifier.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoTextMagnifier.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoTextSelectionToolbar.png b/site/web/assets/images/docs/widget-catalog/CupertinoTextSelectionToolbar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoTextSelectionToolbar.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoTextSelectionToolbar.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoTextSelectionToolbarButton.png b/site/web/assets/images/docs/widget-catalog/CupertinoTextSelectionToolbarButton.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoTextSelectionToolbarButton.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoTextSelectionToolbarButton.png
diff --git a/src/content/assets/images/docs/widget-catalog/CupertinoTimerPicker.png b/site/web/assets/images/docs/widget-catalog/CupertinoTimerPicker.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/CupertinoTimerPicker.png
rename to site/web/assets/images/docs/widget-catalog/CupertinoTimerPicker.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-action-sheet.png b/site/web/assets/images/docs/widget-catalog/cupertino-action-sheet.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-action-sheet.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-action-sheet.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-activity-indicator.png b/site/web/assets/images/docs/widget-catalog/cupertino-activity-indicator.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-activity-indicator.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-activity-indicator.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-alert-dialog.png b/site/web/assets/images/docs/widget-catalog/cupertino-alert-dialog.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-alert-dialog.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-alert-dialog.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-button.png b/site/web/assets/images/docs/widget-catalog/cupertino-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-button.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-context-menu.png b/site/web/assets/images/docs/widget-catalog/cupertino-context-menu.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-context-menu.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-context-menu.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-dialog-action.png b/site/web/assets/images/docs/widget-catalog/cupertino-dialog-action.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-dialog-action.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-dialog-action.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-dialog.png b/site/web/assets/images/docs/widget-catalog/cupertino-dialog.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-dialog.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-dialog.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-form-section.png b/site/web/assets/images/docs/widget-catalog/cupertino-form-section.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-form-section.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-form-section.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-fullscreen-dialog-transition.png b/site/web/assets/images/docs/widget-catalog/cupertino-fullscreen-dialog-transition.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-fullscreen-dialog-transition.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-fullscreen-dialog-transition.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-list-section.png b/site/web/assets/images/docs/widget-catalog/cupertino-list-section.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-list-section.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-list-section.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-list-tile.png b/site/web/assets/images/docs/widget-catalog/cupertino-list-tile.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-list-tile.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-list-tile.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-nav-bar.png b/site/web/assets/images/docs/widget-catalog/cupertino-nav-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-nav-bar.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-nav-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-page-scaffold.png b/site/web/assets/images/docs/widget-catalog/cupertino-page-scaffold.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-page-scaffold.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-page-scaffold.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-page-transition.png b/site/web/assets/images/docs/widget-catalog/cupertino-page-transition.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-page-transition.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-page-transition.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-scrollbar.png b/site/web/assets/images/docs/widget-catalog/cupertino-scrollbar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-scrollbar.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-scrollbar.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-search-field.png b/site/web/assets/images/docs/widget-catalog/cupertino-search-field.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-search-field.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-search-field.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-segmented-control.png b/site/web/assets/images/docs/widget-catalog/cupertino-segmented-control.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-segmented-control.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-segmented-control.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-slider.png b/site/web/assets/images/docs/widget-catalog/cupertino-slider.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-slider.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-slider.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-sliding-segmented-control.png b/site/web/assets/images/docs/widget-catalog/cupertino-sliding-segmented-control.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-sliding-segmented-control.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-sliding-segmented-control.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-sliver-navigation-bar.png b/site/web/assets/images/docs/widget-catalog/cupertino-sliver-navigation-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-sliver-navigation-bar.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-sliver-navigation-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-switch.png b/site/web/assets/images/docs/widget-catalog/cupertino-switch.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-switch.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-switch.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-tab-bar.png b/site/web/assets/images/docs/widget-catalog/cupertino-tab-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-tab-bar.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-tab-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-tab-scaffold.png b/site/web/assets/images/docs/widget-catalog/cupertino-tab-scaffold.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-tab-scaffold.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-tab-scaffold.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-tab-view.png b/site/web/assets/images/docs/widget-catalog/cupertino-tab-view.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-tab-view.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-tab-view.png
diff --git a/src/content/assets/images/docs/widget-catalog/cupertino-textfield.png b/site/web/assets/images/docs/widget-catalog/cupertino-textfield.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/cupertino-textfield.png
rename to site/web/assets/images/docs/widget-catalog/cupertino-textfield.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-badge.png b/site/web/assets/images/docs/widget-catalog/material-3-badge.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-badge.png
rename to site/web/assets/images/docs/widget-catalog/material-3-badge.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-bottom-app-bar.png b/site/web/assets/images/docs/widget-catalog/material-3-bottom-app-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-bottom-app-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-3-bottom-app-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-bottom-sheet.png b/site/web/assets/images/docs/widget-catalog/material-3-bottom-sheet.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-bottom-sheet.png
rename to site/web/assets/images/docs/widget-catalog/material-3-bottom-sheet.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-bubbles.png b/site/web/assets/images/docs/widget-catalog/material-3-bubbles.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-bubbles.png
rename to site/web/assets/images/docs/widget-catalog/material-3-bubbles.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-buttons.png b/site/web/assets/images/docs/widget-catalog/material-3-buttons.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-buttons.png
rename to site/web/assets/images/docs/widget-catalog/material-3-buttons.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-card.png b/site/web/assets/images/docs/widget-catalog/material-3-card.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-card.png
rename to site/web/assets/images/docs/widget-catalog/material-3-card.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-checkbox.png b/site/web/assets/images/docs/widget-catalog/material-3-checkbox.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-checkbox.png
rename to site/web/assets/images/docs/widget-catalog/material-3-checkbox.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-chip.png b/site/web/assets/images/docs/widget-catalog/material-3-chip.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-chip.png
rename to site/web/assets/images/docs/widget-catalog/material-3-chip.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-coral.png b/site/web/assets/images/docs/widget-catalog/material-3-coral.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-coral.png
rename to site/web/assets/images/docs/widget-catalog/material-3-coral.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-date-picker.png b/site/web/assets/images/docs/widget-catalog/material-3-date-picker.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-date-picker.png
rename to site/web/assets/images/docs/widget-catalog/material-3-date-picker.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-dialog.png b/site/web/assets/images/docs/widget-catalog/material-3-dialog.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-dialog.png
rename to site/web/assets/images/docs/widget-catalog/material-3-dialog.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-divider.png b/site/web/assets/images/docs/widget-catalog/material-3-divider.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-divider.png
rename to site/web/assets/images/docs/widget-catalog/material-3-divider.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-extended-fab.png b/site/web/assets/images/docs/widget-catalog/material-3-extended-fab.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-extended-fab.png
rename to site/web/assets/images/docs/widget-catalog/material-3-extended-fab.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-floating-action-button.png b/site/web/assets/images/docs/widget-catalog/material-3-floating-action-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-floating-action-button.png
rename to site/web/assets/images/docs/widget-catalog/material-3-floating-action-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-icon-button.png b/site/web/assets/images/docs/widget-catalog/material-3-icon-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-icon-button.png
rename to site/web/assets/images/docs/widget-catalog/material-3-icon-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-leaves.png b/site/web/assets/images/docs/widget-catalog/material-3-leaves.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-leaves.png
rename to site/web/assets/images/docs/widget-catalog/material-3-leaves.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-list.png b/site/web/assets/images/docs/widget-catalog/material-3-list.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-list.png
rename to site/web/assets/images/docs/widget-catalog/material-3-list.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-menu.png b/site/web/assets/images/docs/widget-catalog/material-3-menu.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-menu.png
rename to site/web/assets/images/docs/widget-catalog/material-3-menu.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-navigation-bar.png b/site/web/assets/images/docs/widget-catalog/material-3-navigation-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-navigation-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-3-navigation-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-navigation-drawer.png b/site/web/assets/images/docs/widget-catalog/material-3-navigation-drawer.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-navigation-drawer.png
rename to site/web/assets/images/docs/widget-catalog/material-3-navigation-drawer.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-navigation-rail.png b/site/web/assets/images/docs/widget-catalog/material-3-navigation-rail.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-navigation-rail.png
rename to site/web/assets/images/docs/widget-catalog/material-3-navigation-rail.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-progress-indicator.png b/site/web/assets/images/docs/widget-catalog/material-3-progress-indicator.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-progress-indicator.png
rename to site/web/assets/images/docs/widget-catalog/material-3-progress-indicator.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-radio-button.png b/site/web/assets/images/docs/widget-catalog/material-3-radio-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-radio-button.png
rename to site/web/assets/images/docs/widget-catalog/material-3-radio-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-search-bar.png b/site/web/assets/images/docs/widget-catalog/material-3-search-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-search-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-3-search-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-segmented-button.png b/site/web/assets/images/docs/widget-catalog/material-3-segmented-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-segmented-button.png
rename to site/web/assets/images/docs/widget-catalog/material-3-segmented-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-side-sheet.png b/site/web/assets/images/docs/widget-catalog/material-3-side-sheet.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-side-sheet.png
rename to site/web/assets/images/docs/widget-catalog/material-3-side-sheet.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-slider.png b/site/web/assets/images/docs/widget-catalog/material-3-slider.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-slider.png
rename to site/web/assets/images/docs/widget-catalog/material-3-slider.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-snackbar.png b/site/web/assets/images/docs/widget-catalog/material-3-snackbar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-snackbar.png
rename to site/web/assets/images/docs/widget-catalog/material-3-snackbar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-switch.png b/site/web/assets/images/docs/widget-catalog/material-3-switch.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-switch.png
rename to site/web/assets/images/docs/widget-catalog/material-3-switch.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-tab-bar.png b/site/web/assets/images/docs/widget-catalog/material-3-tab-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-tab-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-3-tab-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-text-field.png b/site/web/assets/images/docs/widget-catalog/material-3-text-field.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-text-field.png
rename to site/web/assets/images/docs/widget-catalog/material-3-text-field.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-time-picker.png b/site/web/assets/images/docs/widget-catalog/material-3-time-picker.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-time-picker.png
rename to site/web/assets/images/docs/widget-catalog/material-3-time-picker.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-3-top-app-bar.png b/site/web/assets/images/docs/widget-catalog/material-3-top-app-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-3-top-app-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-3-top-app-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-alert-dialog.png b/site/web/assets/images/docs/widget-catalog/material-alert-dialog.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-alert-dialog.png
rename to site/web/assets/images/docs/widget-catalog/material-alert-dialog.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-app-bar.png b/site/web/assets/images/docs/widget-catalog/material-app-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-app-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-app-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-bottom-navigation-bar.png b/site/web/assets/images/docs/widget-catalog/material-bottom-navigation-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-bottom-navigation-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-bottom-navigation-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-bottom-sheets.png b/site/web/assets/images/docs/widget-catalog/material-bottom-sheets.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-bottom-sheets.png
rename to site/web/assets/images/docs/widget-catalog/material-bottom-sheets.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-button-bar.png b/site/web/assets/images/docs/widget-catalog/material-button-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-button-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-button-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-card.png b/site/web/assets/images/docs/widget-catalog/material-card.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-card.png
rename to site/web/assets/images/docs/widget-catalog/material-card.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-carousel.png b/site/web/assets/images/docs/widget-catalog/material-carousel.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-carousel.png
rename to site/web/assets/images/docs/widget-catalog/material-carousel.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-checkbox.png b/site/web/assets/images/docs/widget-catalog/material-checkbox.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-checkbox.png
rename to site/web/assets/images/docs/widget-catalog/material-checkbox.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-chip.png b/site/web/assets/images/docs/widget-catalog/material-chip.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-chip.png
rename to site/web/assets/images/docs/widget-catalog/material-chip.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-circular-progress-indicator.png b/site/web/assets/images/docs/widget-catalog/material-circular-progress-indicator.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-circular-progress-indicator.png
rename to site/web/assets/images/docs/widget-catalog/material-circular-progress-indicator.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-data-table.png b/site/web/assets/images/docs/widget-catalog/material-data-table.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-data-table.png
rename to site/web/assets/images/docs/widget-catalog/material-data-table.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-divider.png b/site/web/assets/images/docs/widget-catalog/material-divider.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-divider.png
rename to site/web/assets/images/docs/widget-catalog/material-divider.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-drawer.png b/site/web/assets/images/docs/widget-catalog/material-drawer.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-drawer.png
rename to site/web/assets/images/docs/widget-catalog/material-drawer.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-elevated-button.png b/site/web/assets/images/docs/widget-catalog/material-elevated-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-elevated-button.png
rename to site/web/assets/images/docs/widget-catalog/material-elevated-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-floating-action-button.png b/site/web/assets/images/docs/widget-catalog/material-floating-action-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-floating-action-button.png
rename to site/web/assets/images/docs/widget-catalog/material-floating-action-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-grid-view.png b/site/web/assets/images/docs/widget-catalog/material-grid-view.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-grid-view.png
rename to site/web/assets/images/docs/widget-catalog/material-grid-view.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-linear-progress-indicator.png b/site/web/assets/images/docs/widget-catalog/material-linear-progress-indicator.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-linear-progress-indicator.png
rename to site/web/assets/images/docs/widget-catalog/material-linear-progress-indicator.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-list-tile.png b/site/web/assets/images/docs/widget-catalog/material-list-tile.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-list-tile.png
rename to site/web/assets/images/docs/widget-catalog/material-list-tile.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-outlined-button.png b/site/web/assets/images/docs/widget-catalog/material-outlined-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-outlined-button.png
rename to site/web/assets/images/docs/widget-catalog/material-outlined-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-popup-menu-button.png b/site/web/assets/images/docs/widget-catalog/material-popup-menu-button.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-popup-menu-button.png
rename to site/web/assets/images/docs/widget-catalog/material-popup-menu-button.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-radio.png b/site/web/assets/images/docs/widget-catalog/material-radio.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-radio.png
rename to site/web/assets/images/docs/widget-catalog/material-radio.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-slider.png b/site/web/assets/images/docs/widget-catalog/material-slider.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-slider.png
rename to site/web/assets/images/docs/widget-catalog/material-slider.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-snack-bar.png b/site/web/assets/images/docs/widget-catalog/material-snack-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-snack-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-snack-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-switch.png b/site/web/assets/images/docs/widget-catalog/material-switch.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-switch.png
rename to site/web/assets/images/docs/widget-catalog/material-switch.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-tab-bar.png b/site/web/assets/images/docs/widget-catalog/material-tab-bar.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-tab-bar.png
rename to site/web/assets/images/docs/widget-catalog/material-tab-bar.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-text-field.png b/site/web/assets/images/docs/widget-catalog/material-text-field.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-text-field.png
rename to site/web/assets/images/docs/widget-catalog/material-text-field.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-tooltip.png b/site/web/assets/images/docs/widget-catalog/material-tooltip.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-tooltip.png
rename to site/web/assets/images/docs/widget-catalog/material-tooltip.png
diff --git a/src/content/assets/images/docs/widget-catalog/material-widgets-app.png b/site/web/assets/images/docs/widget-catalog/material-widgets-app.png
similarity index 100%
rename from src/content/assets/images/docs/widget-catalog/material-widgets-app.png
rename to site/web/assets/images/docs/widget-catalog/material-widgets-app.png
diff --git a/src/content/assets/images/exercise/_README.md b/site/web/assets/images/exercise/_README.md
similarity index 100%
rename from src/content/assets/images/exercise/_README.md
rename to site/web/assets/images/exercise/_README.md
diff --git a/src/content/assets/images/exercise/effects/app-hero/app-hero.jpg b/site/web/assets/images/exercise/effects/app-hero/app-hero.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/app-hero/app-hero.jpg
rename to site/web/assets/images/exercise/effects/app-hero/app-hero.jpg
diff --git a/src/content/assets/images/exercise/effects/instagram-buttons/millennial-dude.jpg b/site/web/assets/images/exercise/effects/instagram-buttons/millennial-dude.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/instagram-buttons/millennial-dude.jpg
rename to site/web/assets/images/exercise/effects/instagram-buttons/millennial-dude.jpg
diff --git a/src/content/assets/images/exercise/effects/instagram-buttons/millennial-texture.jpg b/site/web/assets/images/exercise/effects/instagram-buttons/millennial-texture.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/instagram-buttons/millennial-texture.jpg
rename to site/web/assets/images/exercise/effects/instagram-buttons/millennial-texture.jpg
diff --git a/src/content/assets/images/exercise/effects/parallax/00-header.jpg b/site/web/assets/images/exercise/effects/parallax/00-header.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/parallax/00-header.jpg
rename to site/web/assets/images/exercise/effects/parallax/00-header.jpg
diff --git a/src/content/assets/images/exercise/effects/parallax/01-mount-rushmore.jpg b/site/web/assets/images/exercise/effects/parallax/01-mount-rushmore.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/parallax/01-mount-rushmore.jpg
rename to site/web/assets/images/exercise/effects/parallax/01-mount-rushmore.jpg
diff --git a/src/content/assets/images/exercise/effects/parallax/02-singapore.jpg b/site/web/assets/images/exercise/effects/parallax/02-singapore.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/parallax/02-singapore.jpg
rename to site/web/assets/images/exercise/effects/parallax/02-singapore.jpg
diff --git a/src/content/assets/images/exercise/effects/parallax/03-machu-picchu.jpg b/site/web/assets/images/exercise/effects/parallax/03-machu-picchu.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/parallax/03-machu-picchu.jpg
rename to site/web/assets/images/exercise/effects/parallax/03-machu-picchu.jpg
diff --git a/src/content/assets/images/exercise/effects/parallax/04-vitznau.jpg b/site/web/assets/images/exercise/effects/parallax/04-vitznau.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/parallax/04-vitznau.jpg
rename to site/web/assets/images/exercise/effects/parallax/04-vitznau.jpg
diff --git a/src/content/assets/images/exercise/effects/parallax/05-bali.jpg b/site/web/assets/images/exercise/effects/parallax/05-bali.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/parallax/05-bali.jpg
rename to site/web/assets/images/exercise/effects/parallax/05-bali.jpg
diff --git a/src/content/assets/images/exercise/effects/parallax/06-mexico-city.jpg b/site/web/assets/images/exercise/effects/parallax/06-mexico-city.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/parallax/06-mexico-city.jpg
rename to site/web/assets/images/exercise/effects/parallax/06-mexico-city.jpg
diff --git a/src/content/assets/images/exercise/effects/parallax/07-cairo.jpg b/site/web/assets/images/exercise/effects/parallax/07-cairo.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/parallax/07-cairo.jpg
rename to site/web/assets/images/exercise/effects/parallax/07-cairo.jpg
diff --git a/src/content/assets/images/exercise/effects/split-check/Avatar1.jpg b/site/web/assets/images/exercise/effects/split-check/Avatar1.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/split-check/Avatar1.jpg
rename to site/web/assets/images/exercise/effects/split-check/Avatar1.jpg
diff --git a/src/content/assets/images/exercise/effects/split-check/Avatar2.jpg b/site/web/assets/images/exercise/effects/split-check/Avatar2.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/split-check/Avatar2.jpg
rename to site/web/assets/images/exercise/effects/split-check/Avatar2.jpg
diff --git a/src/content/assets/images/exercise/effects/split-check/Avatar3.jpg b/site/web/assets/images/exercise/effects/split-check/Avatar3.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/split-check/Avatar3.jpg
rename to site/web/assets/images/exercise/effects/split-check/Avatar3.jpg
diff --git a/src/content/assets/images/exercise/effects/split-check/Food1.jpg b/site/web/assets/images/exercise/effects/split-check/Food1.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/split-check/Food1.jpg
rename to site/web/assets/images/exercise/effects/split-check/Food1.jpg
diff --git a/src/content/assets/images/exercise/effects/split-check/Food2.jpg b/site/web/assets/images/exercise/effects/split-check/Food2.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/split-check/Food2.jpg
rename to site/web/assets/images/exercise/effects/split-check/Food2.jpg
diff --git a/src/content/assets/images/exercise/effects/split-check/Food3.jpg b/site/web/assets/images/exercise/effects/split-check/Food3.jpg
similarity index 100%
rename from src/content/assets/images/exercise/effects/split-check/Food3.jpg
rename to site/web/assets/images/exercise/effects/split-check/Food3.jpg
diff --git a/src/content/assets/images/flutter-logo-sharing.png b/site/web/assets/images/flutter-logo-sharing.png
similarity index 100%
rename from src/content/assets/images/flutter-logo-sharing.png
rename to site/web/assets/images/flutter-logo-sharing.png
diff --git a/src/content/assets/images/social/bluesky.svg b/site/web/assets/images/social/bluesky.svg
similarity index 100%
rename from src/content/assets/images/social/bluesky.svg
rename to site/web/assets/images/social/bluesky.svg
diff --git a/src/content/assets/images/social/github.svg b/site/web/assets/images/social/github.svg
similarity index 100%
rename from src/content/assets/images/social/github.svg
rename to site/web/assets/images/social/github.svg
diff --git a/src/content/assets/images/social/google-developers.svg b/site/web/assets/images/social/google-developers.svg
similarity index 100%
rename from src/content/assets/images/social/google-developers.svg
rename to site/web/assets/images/social/google-developers.svg
diff --git a/src/content/assets/images/social/medium.svg b/site/web/assets/images/social/medium.svg
similarity index 100%
rename from src/content/assets/images/social/medium.svg
rename to site/web/assets/images/social/medium.svg
diff --git a/src/content/assets/images/social/x.svg b/site/web/assets/images/social/x.svg
similarity index 100%
rename from src/content/assets/images/social/x.svg
rename to site/web/assets/images/social/x.svg
diff --git a/src/content/assets/images/social/youtube.svg b/site/web/assets/images/social/youtube.svg
similarity index 100%
rename from src/content/assets/images/social/youtube.svg
rename to site/web/assets/images/social/youtube.svg
diff --git a/src/_11ty/filters.ts b/src/_11ty/filters.ts
deleted file mode 100644
index 30f26ce73f8..00000000000
--- a/src/_11ty/filters.ts
+++ /dev/null
@@ -1,247 +0,0 @@
-import { getPageInfo } from './utils/get-page-info.js';
-import { fromHtml } from 'hast-util-from-html';
-import { selectAll } from 'hast-util-select';
-import { toText } from 'hast-util-to-text';
-import { escapeHtml } from 'markdown-it/lib/common/utils.mjs';
-import { UserConfig } from '@11ty/eleventy';
-
-export function registerFilters(eleventyConfig: UserConfig): void {
-  eleventyConfig.addFilter('childPagesOf', function (pages: any[], pageUrl: string) {
-    return pages.filter((page) => page.url.includes(pageUrl) && page.url !== pageUrl);
-  });
-
-  eleventyConfig.addFilter('throwError', function (error: string | null): never {
-    // TODO(parlough): See if more context can be added to this error
-    //   or if there's a better built-in solution.
-    throw new Error(error);
-  });
-
-  eleventyConfig.addFilter('filterByProperty', _filterByProperty);
-  eleventyConfig.addFilter('regexReplace', _regexReplace);
-  eleventyConfig.addFilter('toISOString', _toISOString);
-  eleventyConfig.addFilter('toSimpleDate', _toSimpleDate);
-  eleventyConfig.addFilter('activeNavForPage', _activeNavForPage);
-  eleventyConfig.addFilter('generateToc', _generateToc);
-  eleventyConfig.addFilter('breadcrumbsForPage', _breadcrumbsForPage);
-  eleventyConfig.addFilter('camelCaseBreaker', _camelCaseBreaker);
-  eleventyConfig.addFilter('startsWith', _startsWith);
-}
-
-function _filterByProperty(
-  items: (object | Map)[],
-  property: string,
-  valueToCompareTo: any,
-  useIncludes: boolean = false,
-): any[] {
-  return items.filter(function (item) {
-    const value = item[property];
-    if (value === null) return false;
-
-    if (useIncludes) {
-      return value.includes(valueToCompareTo);
-    }
-
-    return value === valueToCompareTo;
-  });
-}
-
-function _startsWith(content: string, prefix: string): boolean {
-  if (typeof content !== 'string' || typeof prefix !== 'string') {
-    return false;
-  }
-
-  return content.startsWith(prefix);
-}
-
-function _camelCaseBreaker(stringToBreak: string): string {
-  // Only consider non-empty text.
-  if (!stringToBreak
-      || typeof stringToBreak !== 'string'
-      || stringToBreak.length === 0) {
-    return stringToBreak;
-  }
-
-  const firstCharacter = stringToBreak[0];
-  const restOfString = stringToBreak.substring(1);
-
-  // Replace all capital letters in the rest of the string with  + letter.
-  const processedRest =
-      restOfString.replace(/([A-Z])/g, '$&');
-
-  return firstCharacter + processedRest;
-}
-
-/**
- * Replace text in {@link input} that matches the specified {@link regex}
- * with the specified {@link replacement}.
- *
- * @param input
- * @param regex
- * @param replacement
- * @return The resulting string with the replacement made.
- */
-function _regexReplace(input: string, regex: RegExp, replacement: string = ''): string {
-  return input.toString().replace(new RegExp(regex), replacement);
-}
-
-/**
- * Convert a {@link Date} to an ISO string.
- *
- * Used to add date information to the sitemap.
- *
- * @param input The date to convert
- * @return The ISO string
- */
-function _toISOString(input: string | Date): string {
-  if (input instanceof Date) {
-    return input.toISOString();
-  }
-
-  // If it's not a Date object, assume it's already in string format.
-  return input;
-}
-
-function _toSimpleDate(input: string | Date): string {
-  let dateString: string;
-  if (input instanceof Date) {
-    dateString = input.toISOString();
-  } else {
-    // If it's not a Date object, assume it's already in string format.
-    dateString = input;
-  }
-  return dateString.split('T')[0];
-}
-
-function _activeNavForPage(pageUrlPath: string, activeNav: any) {
-  // Split the path for this page, dropping everything before the path:
-  // Example: docs.flutter.dev/cookbook/networking/update-data ->
-  // [cookbook, networking, update-data]
-  const parts = pageUrlPath.toLowerCase().split('/').slice(1);
-  let currentPathPairs = activeNav;
-  let lastAllowedBackupActive = [];
-
-  parts.forEach(part => {
-    // If the current entry has active data,
-    // allow its active data to be a backup if a later path isn't found.
-    const currentEntryActiveData = currentPathPairs['active'];
-    if (currentEntryActiveData) {
-      lastAllowedBackupActive = currentEntryActiveData;
-    }
-
-    const paths = currentPathPairs['paths'];
-
-    // If the current entry has children paths, explore those next.
-    if (paths) {
-      currentPathPairs = paths;
-    }
-
-    // Get the data for the next part.
-    const nextPair = currentPathPairs[part];
-
-    // If the next part of the path doesn't have data,
-    // use the active data for the current backup.
-    if (nextPair === undefined || nextPair === null) {
-      return lastAllowedBackupActive;
-    }
-
-    currentPathPairs = nextPair;
-  });
-
-  // If the last path part has active data, use that,
-  // otherwise fall back to the backup active data.
-  let activeEntries = currentPathPairs['active'];
-  if (activeEntries === undefined || activeEntries === null) {
-    activeEntries = lastAllowedBackupActive;
-  }
-
-  return activeEntries;
-}
-
-function _generateToc(contents: string) {
-  // TODO(parlough): Speed this up.
-  //   Perhaps do the processing before HTML rendering?
-  //   Maybe shouldn't be a filter.
-  const dom = fromHtml(contents, {fragment: true});
-  const headers = selectAll('h2, h3', dom);
-  if (headers.length < 1) {
-    // If there's only one header, there's no point of a TOC.
-    return null;
-  }
-  let currentH2: {text: string, id: string, children: {text: string, id: string}[]} | null = null;
-  const builtToc = [];
-  let count = 0;
-  for (const header of headers) {
-    const id = header.properties['id'];
-    // Header can't be linked to without an ID.
-    if (!id || typeof id !== 'string' || id === '') {
-      continue;
-    }
-
-    // Don't include if no_toc is specified as a class on the header.
-    if ((header.properties['className'] as string | null)?.includes('no_toc')) {
-      continue;
-    }
-
-    // Remove the # added by markdown-it-anchor,
-    // as that's not needed in the TOC.
-    // Also escape any HTML, such as arrow brackets.
-    const text = escapeHtml(toText(header).replace(/#$/, '').trim());
-
-    if (header.tagName === 'h2') {
-      currentH2 = { text: text, id: `#${id}`, children: [] };
-      builtToc.push(currentH2);
-      count += 1;
-    } else if (header.tagName === 'h3') {
-      // A level-3 header must be under a level-2 header.
-      if (currentH2 === null) {
-        throw new Error(`The h3 header "${id}" must be under an h2.`);
-      }
-
-      currentH2.children.push({ text: text, id: `#${id}` });
-      count += 1;
-    }
-  }
-
-  return {
-    toc: builtToc,
-    count: count,
-  };
-}
-
-function _breadcrumbsForPage(page: any): {title: string, url: string}[] {
-  const breadcrumbs = [];
-
-  // Retrieve the liquid data for this page.
-  let data = this.context.environments;
-
-  while (page) {
-    const urlSegments = (page.url as string)
-        .split('/')
-        .filter((segment) => segment.length > 0);
-
-    breadcrumbs.push({
-      title: data['breadcrumb'] ?? data['shortTitle'] ?? data['short-title'] ?? data.title,
-      url: page.url,
-    });
-
-    if (urlSegments.length <= 1) {
-      // If this only has one segment, it's the root page
-      // and has no more parents, so don't continue on.
-      break;
-    } else {
-      // Combine everything but the current segment to find the parent URL.
-      const parentUrl = `/${urlSegments.slice(0, -1).join('/')}/`;
-      // Search for a parent page with the specified URL.
-      const parentPage = getPageInfo(data.collections.all, parentUrl);
-
-      // Store the page information and other data of the parent page.
-      // If no parent page exists, the breadcrumb loop won't continue.
-      page = parentPage?.page;
-      data = parentPage?.data;
-    }
-  }
-
-  // We added the current page first, then found the ancestors,
-  // so reverse since the last ancestor should be to the left.
-  return breadcrumbs.reverse();
-}
diff --git a/src/_11ty/plugins/highlight.ts b/src/_11ty/plugins/highlight.ts
deleted file mode 100644
index 7c537d39f66..00000000000
--- a/src/_11ty/plugins/highlight.ts
+++ /dev/null
@@ -1,633 +0,0 @@
-import { getSingletonHighlighter, Highlighter } from 'shiki';
-import dashDarkTheme from '../syntax/dark-dark.js';
-import dashLightTheme from '../syntax/dash-light.js';
-import MarkdownIt from 'markdown-it';
-import * as hast from 'hast';
-
-const _terminalLanguages = {
-  'console': '$',
-  'ps': 'C:\\>',
-};
-
-/**
- * Replaces the markdown-it code block renderer with our own that:
- *
- * - Parses arguments on the code block meta string.
- * - Uses passed arguments to add a title, show line numbers,
- *   highlight lines, etc.
- * - Wraps the code block in a custom structure for title formatting,
- *   copy buttons, etc.
- * - Syntax highlights the contents according to the specified language
- *   using the shiki package that uses TextMate grammars
- *   and Code-OSS themes.
- *
- * @param markdown The markdown-it instance to configure syntax highlighting for.
- */
-export async function configureHighlighting(markdown: MarkdownIt): Promise {
-  const highlighter = await getSingletonHighlighter({
-    langs: [
-      'dart',
-      'yaml',
-      'json',
-      'swift',
-      'css',
-      'html',
-      'xml',
-      'js',
-      'objc',
-      'bash',
-      'kotlin',
-      'java',
-      'md',
-      'diff',
-      'ps',
-      'console',
-      'cmd',
-      'plaintext',
-      'groovy',
-      'properties',
-      'ruby',
-      'c',
-      'cpp',
-      'csharp',
-      'cmake',
-    ],
-    themes: [dashLightTheme, dashDarkTheme],
-  });
-
-  markdown.renderer.rules.fence = function (tokens, index) {
-    const token = tokens[index]!;
-
-    const splitTokenInfo = token.info.match(/(\S+)\s?(.*?)$/m);
-
-    if (!splitTokenInfo) {
-      throw new Error('Code block missing language specifier.');
-    }
-
-    const language = splitTokenInfo.length > 1 ? splitTokenInfo[1]! : '';
-    const attributes = splitTokenInfo.length > 2 ? splitTokenInfo[2]! : '';
-
-    return _highlight(
-      markdown,
-      highlighter,
-      token.content,
-      language,
-      attributes,
-    );
-  };
-}
-
-/**
- * Highlights the specified {@link content} string, makes replacements,
- * and makes modifications to the output structure based on the
- * passed in {@link attributeString}.
- *
- * @param markdown The markdown-it instance.
- * @param highlighter The shiki highlighter configured with
- *   the correct themes and languages.
- * @param content The content to syntax highlight.
- * @param language The language of the content.
- * @param attributeString The string containing configuration.
- * @returns The processed/highlighted content rendered as HTML.
- */
-function _highlight(
-  markdown: MarkdownIt,
-  highlighter: Highlighter,
-  content: string,
-  language: string,
-  attributeString: string,
-): string {
-  const attributes = _parseAttributes(attributeString);
-
-  // Specially handle DartPad snippets so that inject_embed can convert them.
-  if (language.includes('dartpad')) {
-    const theme = attributes['theme'] ?? 'dark';
-    const title = attributes['title'] ?? 'Runnable Flutter sample';
-    const height = attributes['height'];
-    const runAutomatically = attributes['run'] ?? 'false';
-    return `
${markdown.utils.escapeHtml(content)}
`; - } - - const showLineNumbers = 'showLineNumbers' in attributes; - let startingLineNumber = 0; - if (showLineNumbers) { - const specifiedLineNumber = attributes['showLineNumbers']; - if (specifiedLineNumber != null) { - startingLineNumber = parseInt(specifiedLineNumber, 10); - if (isNaN(startingLineNumber)) { - throw new Error('showLineNumbers must equal a number!'); - } - } - } - - const highlightLines = attributes['highlightLines']; - const linesToHighlight = highlightLines - ? _parseNumbersAndRanges(highlightLines) - : new Set(); - - const isDiff = 'diff' in attributes; - const addedLines = new Set(); - const removedLines = new Set(); - if (isDiff) { - if (showLineNumbers) { - throw new Error('showLineNumbers and diff are not supported on the same code block yet.'); - } - - const lines = content.split('\n'); - for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) { - const line = lines[lineIndex]; - - switch (line.charAt(0)) { - case '+': - addedLines.add(lineIndex + 1); - break; - case '-': - removedLines.add(lineIndex + 1); - break; - } - - lines[lineIndex] = line.substring(2); - } - - content = lines.join('\n'); - } - - const dartpadGistId = attributes['dartpad']; - const noHighlight = 'noHighlight' in attributes; - - // Find the spans enclosed in `[!` and `!]` that we should mark - // and remove them from the text. - const {updatedText, linesToMarkedRanges} = - noHighlight ? { - updatedText: content, - linesToMarkedRanges: {}, - } : - _findMarkedTextAndUpdate(content); - - // Update the content with the markers removed and - // with any extra whitespace trimmed off the end. - content = updatedText.trimEnd(); - - return highlighter.codeToHtml(content, { - lang: language, - themes: { - light: 'dash-light', - dark: 'dash-dark', - }, - transformers: [ - { - pre(preElement) { - // Remove hard coded background color and text color if present. - delete preElement.properties['style']; - - if (showLineNumbers) { - preElement.properties['class'] += ' show-line-numbers'; - } - - if (dartpadGistId && dartpadGistId.length > 5) { - preElement.properties['data-dartpad-id'] = dartpadGistId; - } - - const bodyChildren = [preElement]; - - if (!['plaintext', 'console', 'ps', 'diff', 'powershell'].includes(language)) { - const languageText = _createSpanWithText(language, { - class: 'code-block-language', - title: `Language ${language}`, - }); - bodyChildren.unshift(languageText); - } - - // Create a div container to wrap the `pre` element. - const blockBody: hast.Element = { - type: 'element', - tagName: 'div', - children: bodyChildren, - properties: { - class: 'code-block-body', - }, - }; - - // Add a tag class and element if a tag is specified, - // such as `good` or `bad` in Effective Dart. - const extraTag = attributes['tag']; - if (extraTag) { - blockBody.properties['class'] += ` has-tag tag-${extraTag}`; - - const tagText = - { - good: 'good', - bad: 'bad', - 'passes-sa': '\u2714 static analysis: success', - 'fails-sa': '\u2717 static analysis: failure', - 'runtime-sa': '\u2714 runtime: success', - 'runtime-fail': '\u2717 runtime: failure', - }[extraTag] ?? extraTag; - - const extraTagContent = _createSpanWithText(tagText, { - class: 'code-block-tag', - }); - - bodyChildren.unshift(extraTagContent); - } - - const wrapperChildren: hast.Element[] = []; - - // Add a title if specified, often used for filenames. - const title = attributes['title']; - if (title && title !== '') { - const titleElement: hast.Element = { - type: 'element', - tagName: 'div', - children: [{ type: 'text', value: title }], - properties: { - class: 'code-block-header', - }, - }; - - wrapperChildren.push(titleElement); - } - - wrapperChildren.push(blockBody); - - // Create a div to wrap everything including the title/filename bar. - const wrapper: hast.Element = { - type: 'element', - tagName: 'div', - children: wrapperChildren, - properties: { - class: `code-block-wrapper language-${language}`, - }, - }; - - // Replace the `pre` element with our own wrapper. - return wrapper; - }, - line(lineElement, line) { - if (showLineNumbers) { - lineElement.properties['data-line'] = startingLineNumber + line - 1; - } - - if (linesToHighlight.has(line)) { - lineElement.properties['class'] += ' highlighted-line'; - } else if (addedLines.has(line)) { - lineElement.properties['class'] += ' added-line'; - } else if (removedLines.has(line)) { - lineElement.properties['class'] += ' removed-line'; - } - - if (lineElement.children.length < 1) return; - - if (language in _terminalLanguages) { - // Remove terminal command marker if present. - const firstSpan = lineElement.children[0] as hast.Element; - const firstText = firstSpan.children[0] as hast.Text; - if (firstText?.value.startsWith('$ ')) { - // If a terminal marker is present on the first span, - // remove it and add a class to use CSS to display it. - firstText.value = firstText.value.substring(2); - firstSpan.properties['class'] += ' terminal-command'; - } - } - - const highlightRange = linesToMarkedRanges[line]; - if (highlightRange) { - // If this line has ranges to mark/highlight, do so. - lineElement.children = _wrapMarkedText( - lineElement.children, - highlightRange, - ); - } - }, - }, - ], - }); -} - -// TODO(parlough): Replace this with simpler logic. -const _attributesPattern = /([^\s=]+)(?:="([^"]*)"|=(\S+))?/g; - -/** - * Parse a space-separated attribute string, where spaces in a string literal - * are ignored. - * - * @param attributeString The string containing configuration. - * @return The parsed attributes. - */ -function _parseAttributes(attributeString: string): {[index: string]: string | null} { - const attributes: {[index: string]: string | null} = {}; - if (attributeString === '') return attributes; - - let match: RegExpExecArray | null; - while ((match = _attributesPattern.exec(attributeString))) { - const key = match[1]!; - attributes[key] = match[2] ?? match[3] ?? null; - } - - return attributes; -} - -/** - * Parses a comma-separated list of numbers and ranges into a set of numbers. - * - * @param input A comma-separated list of numbers and ranges. - * @returns All unique numbers specified in the input. - */ -function _parseNumbersAndRanges(input: string): Set { - const elements = input.split(','); - const combinedNumbers = new Set(); - - for (const element of elements) { - const rangeParts = element.split('-'); - - // If it includes a dash, it's (hopefully) a range between two numbers. - if (rangeParts.length > 1) { - // Split by the dash, and turn each string into a number. - // Assume the user only included one dash. - const start = Number.parseInt(rangeParts[0]); - const end = Number.parseInt(rangeParts[1]); - if (start && end && !Number.isNaN(start) && !Number.isNaN(end)) { - for (let i = start; i <= end; i++) { - combinedNumbers.add(i); - } - } - } else { - // It's (hopefully) just a single number. - const number = Number.parseInt(element); - if (number && !Number.isNaN(number)) { - combinedNumbers.add(number); - } - } - } - - return combinedNumbers; -} - -/** - * Wraps the text within the given list of {@link spans} with `` tags - * based on the provided {@link ranges}. - * - * The spans and ranges should be - * ordered corresponding to the source line of text. - * - * @param spans The list of spans to wrap the text of. - * @param ranges The ranges in the text to mark. - * @returns A new list of spans with tags added - * around the specified ranges. - */ -function _wrapMarkedText( - spans: hast.ElementContent[], - ranges: {startIndex: number, endIndex: number}[], -): hast.Element[] { - /** - * The current index in the text across all spans. - */ - let currentIndexInLine = 0; - - /** - * The index of the current range being marked. - */ - let currentRangeIndex = 0; - - /** - * The new collection of spans to replace the original. - */ - const updatedSpans: hast.Element[] = []; - - /** - * The mark to wrap the current range with. - */ - let markElement = _createEmptyMarkElement(); - - for (const span of spans) { - if (span.type === 'text' || span.type === 'comment') { - throw new Error(`Expected only spans when wrapping, but found: ${span.type}.`); - } - const [child, ...otherChildren] = span.children; - if (!child || otherChildren.length > 0 || child.type !== 'text') { - throw new Error('Each span should have exactly one text child.'); - } - - /** The text within the current span. */ - const text = child.value; - - /** - * The properties that all potentially created children should have too. - */ - const spanProperties: hast.Properties = span.properties ?? {}; - - /** - * The current index within the current span. - */ - let indexInCurrentSpan = 0; - - // Multiple ranges can occur within the same collection of spans, - // or even within the same span. - // So we need to keep track of which range we're currently searching for. - // Use indices to loop through the ranges as it's cheaper - // than modifying the entire array with `shift`. - while ( - currentRangeIndex < ranges.length && - indexInCurrentSpan < text.length - ) { - const { startIndex: rangeStartIndex, endIndex: rangeEndIndex } = - ranges[currentRangeIndex]!; - - /** - * The index in relation to the start of the current span - * where the current range starts or the index in the current span if - * the range starts before the current index. - */ - const relativeRangeStartIndex = Math.max( - rangeStartIndex - currentIndexInLine, - indexInCurrentSpan, - ); - - /** - * The index in relation to the start of the current span - * where the current range ends or the ending index of the current span if - * the range ends after the current index. - */ - const relativeEndIndex = Math.min( - rangeEndIndex - currentIndexInLine, - text.length, - ); - - // If `indexInCurrentSpan` is less than `relativeRangeStartIndex`, - // all text between the two shouldn't be marked. - if (indexInCurrentSpan < relativeRangeStartIndex) { - updatedSpans.push( - _createSpanWithText( - text.slice(indexInCurrentSpan, relativeRangeStartIndex), - spanProperties, - ), - ); - } - - // If `relativeRangeStartIndex` is less than `relativeEndIndex`, - // the text within that range should be marked. - if (relativeRangeStartIndex < relativeEndIndex) { - markElement.children.push( - _createSpanWithText( - text.slice(relativeRangeStartIndex, relativeEndIndex), - spanProperties, - ), - ); - } - - /** - * The index in the whole line of the end of the current range if - * it has all been marked, otherwise the index in the whole line - * of the end of the current span. - */ - const rangeOrSpanEndIndexInLine = currentIndexInLine + relativeEndIndex; - - // If `rangeOrSpanEndIndexInLine` is greater than `rangeEndIndex`, - // the end of the current range was in this span, - // so it's mark element is complete. - if (rangeOrSpanEndIndexInLine >= rangeEndIndex) { - // Add the completed mark element for the range, - // then move to the next range. - updatedSpans.push(markElement); - markElement = _createEmptyMarkElement(); - currentRangeIndex++; - } - - // Move to the end of the current range if it was in the current span, - // otherwise to the end of the span. - indexInCurrentSpan = relativeEndIndex; - } - - // If the entire span hasn't been included yet, - // add the rest of it. - if (indexInCurrentSpan < text.length) { - updatedSpans.push( - _createSpanWithText(text.slice(indexInCurrentSpan), spanProperties), - ); - } - - // Move to the next span by adding the current span's - // text length to the current index. - currentIndexInLine += text.length; - } - - return updatedSpans; -} - -/** - * Creates a new mark element with the `highlight` class and no children. - * - * @returns The created hast HTML element. - */ -function _createEmptyMarkElement(): hast.Element { - return { - type: 'element', - tagName: 'mark', - children: [], - properties: { - class: 'highlight', - }, - }; -} - -/** - * Creates a new hast span element with the specified - * inline {@link text}, and {@link properties}. - * - * @param text The text to include in the HTML element. - * @param properties The properties to specify for the HTML element, - * such as classes to add. - * @returns The created hast HTML element. - */ -function _createSpanWithText(text: string, properties: hast.Properties = {}): hast.Element { - return { - type: 'element', - tagName: 'span', - children: [{ type: 'text', value: text }], - properties: properties, - }; -} - -/** - * Searches through the specified {@link text} and finds all instances of - * text marked with a `[!` and `!]`. - * Returns the start and end indices of each instance of marked text, - * as well as the updated text with all the open and close markers removed. - * - * @param text The text to search through and potentially update. - * @returns The updated text and the indices of marked text in each line. - */ -function _findMarkedTextAndUpdate(text: string): { - updatedText: string, - linesToMarkedRanges: { [p: number]: { startIndex: number; endIndex: number }[] }; -} { - const lines = text.split('\n'); - - const linesToMarkedRanges: {[index: number]: {startIndex: number, endIndex: number}[]} = {}; - const textWithMarksRemoved: string[] = []; - - for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { - const line = lines[lineIndex]!; - let currentIndexInLine = 0; - - /** - * The updated line with the marks (`[!` and `!]`) removed. - */ - let updatedLine = ''; - - /** - * The ranges of marked text in the current line. - */ - let markedRanges: {startIndex: number, endIndex: number}[] = []; - - while (currentIndexInLine < line.length) { - const startIndex = line.indexOf('[!', currentIndexInLine); - - // If there are no more opening markers, add the rest of the line. - if (startIndex === -1) { - updatedLine += line.slice(currentIndexInLine); - break; - } - - const endIndex = line.indexOf('!]', startIndex); - if (endIndex === -1) { - throw new Error(`Invalid syntax in line ${lineIndex + 1}. - An opening marker was found, but no closing marker was found.`); - } - - // Add text before marker to the updated line. - updatedLine += line.slice(currentIndexInLine, startIndex); - - // Track the marked text range. - markedRanges.push({ - // We haven't added the marker to the updated line yet, - // so the start index is the length of the updated line. - startIndex: updatedLine.length, - // Subtract the start index from the end index to - // get the length of the marked text, - // then subtract 2 to account for the length of the included marker. - endIndex: updatedLine.length + (endIndex - startIndex - 2), - }); - - // Skip the marker and add the marked text to the updated line. - updatedLine += line.slice(startIndex + 2, endIndex); - - // Update the search start index to continue searching after the marker. - currentIndexInLine = endIndex + 2; - } - - // If there were marked ranges in the current line, track them. - if (markedRanges.length > 0) { - // Point the line number to the marked ranges. - // Add 1 to the line index because lines start at 1, not 0. - linesToMarkedRanges[lineIndex + 1] = markedRanges; - } - - textWithMarksRemoved.push(updatedLine); - } - - return { - linesToMarkedRanges: linesToMarkedRanges, - updatedText: textWithMarksRemoved.join('\n'), - }; -} diff --git a/src/_11ty/plugins/markdown.ts b/src/_11ty/plugins/markdown.ts deleted file mode 100644 index 6e8e6b8c4ed..00000000000 --- a/src/_11ty/plugins/markdown.ts +++ /dev/null @@ -1,111 +0,0 @@ -import MarkdownIt from 'markdown-it'; -import markdownItContainer from 'markdown-it-container'; -import markdownItDefinitionList from 'markdown-it-deflist'; -import markdownItFootnote from 'markdown-it-footnote'; -import markdownItAttrs from 'markdown-it-attrs'; -import markdownItAnchor from 'markdown-it-anchor'; -import { slugify } from '../utils/slugify.js'; - -export const markdown = (() => { - const markdown = new MarkdownIt({ html: true }) - .use(markdownItDefinitionList) - .use(markdownItFootnote) - .use(markdownItAttrs, { - leftDelimiter: '{:', - rightDelimiter: '}', - }) - .use(markdownItAnchor, { - slugify: (s) => slugify(s), - level: 2, - tabIndex: false, - permalink: markdownItAnchor.permalink.linkAfterHeader({ - style: 'aria-label', - assistiveText: title => `Link to '${title}' section`, - symbol: '#', - class: 'heading-link', - wrapper: ['
', '
'] - }), - }); - - _registerAsides(markdown); - _setUpTables(markdown); - - return markdown; -})(); - -/** - * Wrap all tables in a div with `table-wrapper` class. - */ -function _setUpTables(markdown: MarkdownIt): void { - markdown.renderer.rules = { - ...markdown.renderer.rules, - table_open: function (tokens, idx, _options, _env, self) { - const token = tokens[idx]!; - // Render added attributes from `{:.table .table-striped}` syntax. - return `
\n
\n`; - }, - table_close: () => '
\n', - }; -} - -/** - * Register a custom aside/admonition. - * - * @param markdown - * @param id The name to use in Markdown to create the aside. - * @param defaultTitle The title to use if no title is specified in Markdown. - * @param icon The material icon to use in the aside. - * @param style The classes to add to the aside. - */ -function _registerAside(markdown: MarkdownIt, id: string, defaultTitle: string | null, icon: string | null, style: string): void { - markdown.use(markdownItContainer, id, { - render: function (tokens: any[], index: number) { - if (tokens[index].nesting === 1) { - const parsedArgs = /\s+(.*)/.exec(tokens[index].info); - - const title = parsedArgs?.[1] ?? defaultTitle; - return `\n'; - } - }, - }); -} - -/** - * Registers the custom asides/admonitions used on the site. - */ -function _registerAsides(markdown: MarkdownIt): void { - _registerAside(markdown, 'note', 'Note', 'info', 'alert-info'); - _registerAside( - markdown, - 'flutter-note', - 'Flutter note', - 'flutter', - 'alert-info', - ); - _registerAside( - markdown, - 'version-note', - 'Version note', - 'merge_type', - 'alert-info', - ); - _registerAside(markdown, 'tip', 'Tip', 'lightbulb', 'alert-success'); - _registerAside(markdown, 'recommend', 'Recommended', 'bolt', 'alert-success'); - _registerAside(markdown, 'important', 'Important', 'error', 'alert-important'); - _registerAside( - markdown, - 'warning', - 'Warning', - 'warning', - 'alert-warning', - ); - - _registerAside(markdown, 'secondary', null, null, 'alert-secondary'); -} diff --git a/src/_11ty/shortcodes.ts b/src/_11ty/shortcodes.ts deleted file mode 100644 index fafa88e1c00..00000000000 --- a/src/_11ty/shortcodes.ts +++ /dev/null @@ -1,130 +0,0 @@ -import {UserConfig} from '@11ty/eleventy'; -import {slugify} from './utils/slugify.js'; -import {fromHtml} from 'hast-util-from-html'; -import {selectAll} from 'hast-util-select'; -import {toHtml} from 'hast-util-to-html'; -import {escapeHtml} from 'markdown-it/lib/common/utils.mjs'; - -export function registerShortcodes(eleventyConfig: UserConfig): void { - _setupTabs(eleventyConfig); - _setupMedia(eleventyConfig); - _setupOsSelector(eleventyConfig); -} - -function _setupOsSelector(eleventyConfig: UserConfig): void { - eleventyConfig.addShortcode('osSelector', function () { - const osNames = ['Windows', 'macOS', 'Linux', 'ChromeOS']; - - function createOsButton(osName: string, selected: boolean = false) { - const osId = osName.toLowerCase(); - return ` -`; - } - - return ` -
- ${osNames.map((osName) => { - return createOsButton(osName, osName === 'Windows'); - }).join('\n')} -
`; - }); -} - -function _setupMedia(eleventyConfig: UserConfig): void { - eleventyConfig.addShortcode('ytEmbed', function (id: string, title: string, fullWidth = false) { - const escapedTitle = title && title.length > 0 ? escapeHtml(title) : ''; - - let startTime = 0; - if (id.includes('?')) { - id = id.split('?')[0]; - - const idAndStartTime = id.split('start='); - if (idAndStartTime.length > 1) { - const startTimeString = idAndStartTime[1]; - startTime = Number.parseInt(startTimeString); - } - } - - return ` - -

Watch on YouTube in a new tab: "${title}"

-
`; - }); - - eleventyConfig.addPairedShortcode('videoWrapper', function (content: string, intro = '') { - let wrapperMarkup = '
'; - if (intro && intro !== '') { - wrapperMarkup += `${intro}`; - } - - wrapperMarkup += content; - wrapperMarkup += '
'; - return wrapperMarkup; - }); -} - -function _setupTabs(eleventyConfig: UserConfig) { - // Counter shared between all tabs and wrappers to - // ensure each has a unique ID. - let currentTabWrapperId = 0; - let currentTabPaneId = 0; - - eleventyConfig.addPairedShortcode('tabs', function (content: string, saveKey: string, wrapped: boolean = false) { - const tabWrapperId = currentTabWrapperId++; - let tabMarkup = `
\n'; - tabMarkup += toHtml(tabPanes); - tabMarkup += '\n
'; - - return tabMarkup; - }); - - eleventyConfig.addPairedShortcode('tab', function (content: string, tabName: string) { - const tabIdNumber = currentTabPaneId++; - const tabId = `${tabIdNumber}-tab`; - const tabPanelId = `${tabId}-panel`; - return `
- -${content} - -
-`; - }); -} diff --git a/src/_11ty/syntax/dark-dark.ts b/src/_11ty/syntax/dark-dark.ts deleted file mode 100644 index 6ed8c659353..00000000000 --- a/src/_11ty/syntax/dark-dark.ts +++ /dev/null @@ -1,140 +0,0 @@ -// This is the dark mode version of the -// syntax highlighting theme for code blocks on the website. -// It's imported and used by `src/_11ty/plugins/highlight.ts`. -export default { - name: 'dash-dark', - colors: { - 'editor.background': '#242b32', - 'editor.foreground': '#dcdcdc', - }, - tokenColors: [ - { - settings: { - background: '#242b32', - foreground: '#dcdcdc', - }, - }, - { - scope: 'emphasis', - settings: { - fontStyle: 'italic', - }, - }, - { - scope: 'strong', - settings: { - fontStyle: 'bold', - }, - }, - { - scope: [ - 'punctuation', - 'punctuation.separator.inheritance-clause', - 'storage.modifier.package.java', - ], - settings: { - foreground: '#dcdcdc', - }, - }, - { - scope: ['comment', 'punctuation.definition.comment'], - settings: { - foreground: '#8B95A7', - }, - }, - { - scope: 'constant', - settings: { - foreground: '#1CDAC5', - }, - }, - { - scope: [ - 'keyword', - 'storage.modifier', - 'storage.type', - 'variable.language', - ], - settings: { - foreground: '#FF897E', - }, - }, - { - scope: [ - 'keyword.operator', - 'string.interpolated.expression', - 'constant.character.escape', - ], - settings: { - foreground: '#E1E2EC', - }, - }, - { - scope: ['string', 'string.interpolated', 'punctuation.definition.string'], - settings: { - foreground: '#1CDAC5', - }, - }, - { - scope: [ - 'entity.name.function', - 'support.function', - 'entity.other.attribute-name', - ], - settings: { - foreground: '#B581FF', - }, - }, - { - scope: [ - 'entity.name.class', - 'entity.name.type', - 'entity.name.type.class', - 'entity.name.type.enum', - 'entity.name.type.protocol', - 'support.class', - 'support.type', - 'entity.name.tag', - ], - settings: { - foreground: '#6bb1ff', - }, - }, - { - scope: ['variable', 'variable.other'], - settings: { - foreground: '#E1E2EC', - }, - }, - { - scope: 'markup.underline', - settings: { - fontStyle: 'underline', - }, - }, - { - scope: 'markup.bold', - settings: { - fontStyle: 'bold', - }, - }, - { - scope: 'markup.heading', - settings: { - fontStyle: 'bold', - }, - }, - { - scope: 'markup.italic', - settings: { - fontStyle: 'italic', - }, - }, - { - scope: 'markup.strikethrough', - settings: { - fontStyle: 'strikethrough', - }, - }, - ], -}; diff --git a/src/_11ty/syntax/dash-light.ts b/src/_11ty/syntax/dash-light.ts deleted file mode 100644 index 6226f53ef3a..00000000000 --- a/src/_11ty/syntax/dash-light.ts +++ /dev/null @@ -1,140 +0,0 @@ -// This is the light mode version of the -// syntax highlighting theme for code blocks on the website. -// It's imported and used by `src/_11ty/plugins/highlight.ts`. -export default { - name: 'dash-light', - colors: { - 'editor.background': '#ECEDF7', - 'editor.foreground': '#191C22', - }, - tokenColors: [ - { - settings: { - background: '#ECEDF7', - foreground: '#191C22', - }, - }, - { - scope: 'emphasis', - settings: { - fontStyle: 'italic', - }, - }, - { - scope: 'strong', - settings: { - fontStyle: 'bold', - }, - }, - { - scope: [ - 'punctuation', - 'punctuation.separator.inheritance-clause', - 'storage.modifier.package.java', - ], - settings: { - foreground: '#191C22', - }, - }, - { - scope: ['comment', 'punctuation.definition.comment'], - settings: { - foreground: '#59616E', - }, - }, - { - scope: 'constant', - settings: { - foreground: '#0C7064', - }, - }, - { - scope: [ - 'keyword', - 'storage.modifier', - 'storage.type', - 'variable.language', - ], - settings: { - foreground: '#BD2314', - }, - }, - { - scope: [ - 'keyword.operator', - 'string.interpolated.expression', - 'constant.character.escape', - ], - settings: { - foreground: '#191C22', - }, - }, - { - scope: ['string', 'string.interpolated', 'punctuation.definition.string'], - settings: { - foreground: '#0C7064', - }, - }, - { - scope: [ - 'entity.name.function', - 'support.function', - 'entity.other.attribute-name', - ], - settings: { - foreground: '#6200EE', - }, - }, - { - scope: [ - 'entity.name.class', - 'entity.name.type', - 'entity.name.type.class', - 'entity.name.type.enum', - 'entity.name.type.protocol', - 'support.class', - 'support.type', - 'entity.name.tag', - ], - settings: { - foreground: '#146BCD', - }, - }, - { - scope: ['variable', 'variable.other'], - settings: { - foreground: '#191C22', - }, - }, - { - scope: 'markup.underline', - settings: { - fontStyle: 'underline', - }, - }, - { - scope: 'markup.bold', - settings: { - fontStyle: 'bold', - }, - }, - { - scope: 'markup.heading', - settings: { - fontStyle: 'bold', - }, - }, - { - scope: 'markup.italic', - settings: { - fontStyle: 'italic', - }, - }, - { - scope: 'markup.strikethrough', - settings: { - fontStyle: 'strikethrough', - }, - }, - ], -}; diff --git a/src/_11ty/utils/get-page-info.ts b/src/_11ty/utils/get-page-info.ts deleted file mode 100644 index e2df4173fd8..00000000000 --- a/src/_11ty/utils/get-page-info.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Get the 11ty info and data from the page at the specified {@link url} - * using the 11ty collection of {@link pages}. - * - * @param pages The `11ty` collection of pages. - * @param url The URL of the page to look for the data for. - * @return The info and data of the found page. - */ -export function getPageInfo(pages: any[], url: string): any { - const cached = _cachedPages.get(url); - if (cached) { - return cached; - } - - for (const page of pages) { - if (page.url === url) { - _cachedPages.set(url, page); - return page; - } - } -} - -/** - * A cache of page URLs to their 11ty page information and data. - */ -const _cachedPages = new Map(); // TODO(parlough): Replace this. diff --git a/src/_11ty/utils/slugify.ts b/src/_11ty/utils/slugify.ts deleted file mode 100644 index 617678a1a21..00000000000 --- a/src/_11ty/utils/slugify.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Converts the specified text, usually header, - * into a valid slug for URL fragments. - * - * @param text The text to convert - * @returns The converted text - */ -export function slugify(text: string): string { - if (!text || text.length === 0) { - return text; - } - - return text - .toLowerCase() - .trim() - .replace(/\+/g, 'plus') - .replace(/[:.]/g, '-') - .replace(/[^\p{L}\p{N}\s:._-]/gu, '') - .replace(/[\s-]+/g, '-') - .replace(/^-+|-+$/g, ''); -} diff --git a/src/_data/devtools_releases.yml b/src/_data/devtools_releases.yml deleted file mode 100644 index e632d05af23..00000000000 --- a/src/_data/devtools_releases.yml +++ /dev/null @@ -1,52 +0,0 @@ -# When adding the release notes for a new DevTools release, -# make sure to add the version number as an entry in this list. -# This step might be eliminated in the future. -releases: - - '2.51.0' - - '2.50.0' - - '2.49.0' - - '2.48.0' - - '2.47.0' - - '2.46.0' - - '2.45.0' - - '2.44.0' - - '2.42.3' - - '2.41.0' - - '2.40.2' - - '2.39.0' - - '2.38.0' - - '2.37.2' - - '2.36.0' - - '2.35.0' - - '2.34.1' - - '2.33.0' - - '2.32.0' - - '2.31.0' - - '2.30.0' - - '2.29.0' - - '2.28.5' - - '2.28.4' - - '2.28.3' - - '2.27.0' - - '2.26.1' - - '2.25.0' - - '2.24.0' - - '2.23.1' - - '2.22.2' - - '2.21.1' - - '2.20.0' - - '2.19.0' - - '2.18.0' - - '2.17.0' - - '2.16.0' - - '2.15.0' - - '2.14.0' - - '2.13.1' - - '2.12.2' - - '2.12.1' - - '2.11.2' - - '2.10.0' - - '2.9.2' - - '2.9.1' - - '2.8.0' - - '2.7.0' diff --git a/src/_data/eleventyComputed.js b/src/_data/eleventyComputed.js deleted file mode 100644 index c2c2ae95554..00000000000 --- a/src/_data/eleventyComputed.js +++ /dev/null @@ -1,105 +0,0 @@ -// noinspection JSUnusedGlobalSymbols -export default { - activeNav: (data) => { - const sidenav = data['sidenav']; - - const results = {}; - _visitPermalinks(results, sidenav, []); - return results; - }, -}; - -/** - * - * @param results {object} - * @param navTree {object[]} - * @param path {number[]} - * @private - */ -function _visitPermalinks(results, navTree, path) { - navTree.forEach((entry, i) => { - const permalink = entry['permalink']; - const newPath = [...path, i + 1]; - const children = entry['children']; - const hasChildren = Array.isArray(children); - - if (typeof permalink === 'string' || permalink instanceof String) { - _addLink(results, permalink, newPath, hasChildren); - } - - if (hasChildren) { - _visitPermalinks(results, children, newPath); - } - }); -} - -/** - * - * @param results {object} - * @param permalink {string} - * @param path {number[]} - * @param hasChildren {boolean} - * @private - */ -function _addLink(results, permalink, path, hasChildren) { - // Skip external links. - if (permalink.startsWith('http')) { - return; - } - - // Throw an error if a permalink doesn't start with a `/`. - if (!permalink.startsWith('/')) { - throw new Error(`${permalink} does not begin with a '/'`); - } - - // Split the specified permalink into parts. - const parts = permalink.split('/'); - - // Add active nav data for the specified permalink. - _addPart(results, path, parts, 1, hasChildren); -} - -/** - * - * @param result {object} - * @param path {number[]} - * @param parts {string[]} - * @param index {number} - * @param hasChildren {boolean} - * @private - */ -function _addPart(result, path, parts, index, hasChildren = false) { - const isLast = index === parts.length - 1; - let current = result[parts[index]]; - - if (!current) { - // If the current part isn't in the results map yet, add a new map. - current = {}; - result[parts[index]] = current; - } - - // If this is the last part of the path, - // store the active nav data. - if (isLast) { - const active = current['active']; - // Override active nav data if - // it doesn't already exist for this part, - // or the current active data was from an entry with children. - if (!active) { - current['active'] = path; - if (hasChildren) { - current['has-children'] = true; - } - } else if (!hasChildren && current['has-children'] === true) { - current['active'] = path; - current['has-children'] = false; - } - } else { - if (!current['paths']) { - current['paths'] = {}; - } - - // Continue to the next part. - _addPart(current['paths'], path, parts, index + 1, hasChildren); - } -} diff --git a/src/_data/layout.js b/src/_data/layout.js deleted file mode 100644 index 4c8d877ddd3..00000000000 --- a/src/_data/layout.js +++ /dev/null @@ -1 +0,0 @@ -export default 'default.html'; diff --git a/src/_data/learning-resources-index/filters.yml b/src/_data/learning-resources-index/filters.yml deleted file mode 100644 index 27b57d6891f..00000000000 --- a/src/_data/learning-resources-index/filters.yml +++ /dev/null @@ -1,23 +0,0 @@ -tags: - - AI - - Animation - - Architecture - - Cupertino - - Design - - Desktop - - Firebase - - Good for beginners - - Google APIs - - iOS - - Layout - - Material - - Routing and navigation - - State management - - Testing - - Web - - Widgets -type: - - Tutorial - - Sample code - - Workshop - - Recipe diff --git a/src/_includes/banner.html b/src/_includes/banner.html deleted file mode 100644 index b9a904ba1c6..00000000000 --- a/src/_includes/banner.html +++ /dev/null @@ -1 +0,0 @@ -Build high quality, feature-rich apps with the new Flutter Extension for Gemini CLI. Learn more
diff --git a/src/_includes/breadcrumbs.html b/src/_includes/breadcrumbs.html deleted file mode 100644 index ab55161cf6d..00000000000 --- a/src/_includes/breadcrumbs.html +++ /dev/null @@ -1,32 +0,0 @@ -{% comment %} -Embeds breadcrumb RDFa, follows ARIA guidelines. References: -- https://developers.google.com/search/docs/data-types/breadcrumb -- https://schema.org/BreadcrumbList -- https://www.w3.org/TR/wai-aria-practices/examples/breadcrumb/index.html -- https://search.google.com/structured-data/testing-tool -{% endcomment %} - -{% assign url = page.url | regexReplace: '/index$|/index.html$|/$' -%} - -{% if url.size > 0 -%} -{% assign breadcrumbs = page | breadcrumbsForPage -%} -{% if breadcrumbs -%} - -{% endif -%} -{%- endif -%} diff --git a/src/_includes/cookie-notice.html b/src/_includes/cookie-notice.html deleted file mode 100644 index df3b02805d0..00000000000 --- a/src/_includes/cookie-notice.html +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/src/_includes/docs/add-to-app/android-initial-route-cached-engine.md b/src/_includes/docs/add-to-app/android-initial-route-cached-engine.md index ec46e8eb2a1..18ddb766a44 100644 --- a/src/_includes/docs/add-to-app/android-initial-route-cached-engine.md +++ b/src/_includes/docs/add-to-app/android-initial-route-cached-engine.md @@ -12,8 +12,8 @@ with a custom initial route can configure their cached executing the Dart entrypoint. The following example demonstrates the use of an initial route with a cached engine: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyApplication.kt" class MyApplication : Application() { @@ -36,8 +36,8 @@ class MyApplication : Application() { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyApplication.java" public class MyApplication extends Application { @@ -60,8 +60,8 @@ public class MyApplication extends Application { } ``` -{% endtab %} -{% endtabs %} + + By setting the initial route of the navigation channel, the associated `FlutterEngine` displays the desired route upon initial execution of the @@ -73,4 +73,3 @@ Developers who would like to use the same `FlutterEngine` between different `Activity`s and `Fragment`s and switch the route between those displays need to set up a method channel and explicitly instruct their Dart code to change `Navigator` routes. - diff --git a/src/_includes/docs/add-to-app/ios-project/embed-cocoapods.md b/src/_includes/docs/add-to-app/ios-project/embed-cocoapods.md index fe9941217f0..e2a6e406325 100644 --- a/src/_includes/docs/add-to-app/ios-project/embed-cocoapods.md +++ b/src/_includes/docs/add-to-app/ios-project/embed-cocoapods.md @@ -20,7 +20,7 @@ consult the [CocoaPods getting started guide][]. If watching a video helps you learn, this video covers adding Flutter to an iOS app: -{% ytEmbed 'IIcrfrTshTs', 'Step by step on how to add Flutter to an existing iOS app' %} + #### Requirements {:#method-a-reqs} diff --git a/src/_includes/docs/add-to-app/ios-project/embed-frameworks.md b/src/_includes/docs/add-to-app/ios-project/embed-frameworks.md index 36c1331f6ca..a0b39ed8bed 100644 --- a/src/_includes/docs/add-to-app/ios-project/embed-frameworks.md +++ b/src/_includes/docs/add-to-app/ios-project/embed-frameworks.md @@ -18,11 +18,11 @@ Use this method in the following use cases: #### Limitations {:#method-b-limits} -{% render docs/add-to-app/ios-project/limits-common-deps.md %} +{% render "docs/add-to-app/ios-project/limits-common-deps.md" %} #### Example project structure {:#method-b-structure} -{% render docs/add-to-app/ios-project/embed-framework-directory-tree.md %} +{% render "docs/add-to-app/ios-project/embed-framework-directory-tree.md" %} #### Procedures @@ -32,6 +32,6 @@ into your existing app in Xcode depends on the type of framework. * Link and embed dynamic frameworks. * Link static frameworks. [Never embed them][static-framework]. -{% render docs/add-to-app/ios-project/link-and-embed.md %} +{% render "docs/add-to-app/ios-project/link-and-embed.md" %} [static-framework]: https://developer.apple.com/library/archive/technotes/tn2435/_index.html diff --git a/src/_includes/docs/add-to-app/ios-project/embed-split.md b/src/_includes/docs/add-to-app/ios-project/embed-split.md index 9d1e823065c..ff7c8b35a3b 100644 --- a/src/_includes/docs/add-to-app/ios-project/embed-split.md +++ b/src/_includes/docs/add-to-app/ios-project/embed-split.md @@ -19,7 +19,7 @@ Use this method in the following use cases: #### Limitations {:#method-c-limits} -{% render docs/add-to-app/ios-project/limits-common-deps.md %} +{% render "docs/add-to-app/ios-project/limits-common-deps.md" %} This method only works with the `beta` or `stable` [release channels][]. @@ -27,7 +27,7 @@ This method only works with the `beta` or `stable` [release channels][]. #### Example project structure {:#method-c-structure} -{% render docs/add-to-app/ios-project/embed-framework-directory-tree.md %} +{% render "docs/add-to-app/ios-project/embed-framework-directory-tree.md" %} #### Add Flutter engine to your Podfile @@ -45,4 +45,4 @@ and `Release` when you're ready to ship. #### Link and embed app and plugin frameworks -{% render docs/add-to-app/ios-project/link-and-embed.md %} +{% render "docs/add-to-app/ios-project/link-and-embed.md" %} diff --git a/src/_includes/docs/add-to-app/ios-project/link-and-embed.md b/src/_includes/docs/add-to-app/ios-project/link-and-embed.md index d021d399c76..b8ca21d0919 100644 --- a/src/_includes/docs/add-to-app/ios-project/link-and-embed.md +++ b/src/_includes/docs/add-to-app/ios-project/link-and-embed.md @@ -18,7 +18,7 @@ To link the necessary frameworks, follow this procedure. 1. Expand **Link Binary With Libraries**. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/linked-libraries.png", caption:"Expand the **Link Binary With Libraries** build phase in Xcode" %} + 1. Click **+** (plus sign). @@ -29,7 +29,7 @@ To link the necessary frameworks, follow this procedure. 1. Command-click the frameworks in that directory then click **Open**. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/choose-libraries.png", caption:"Choose frameworks to link from the **Choose frameworks and libraries to add:** dialog box in Xcode" %} + 1. Update the paths to the libraries to account for build modes. @@ -43,7 +43,7 @@ To link the necessary frameworks, follow this procedure. 1. Open `project.pbxproj` with Xcode. The file opens in Xcode's text editor. This also locks **Project Navigator** until you close the text editor. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/project-pbxproj.png", caption:"The `project-pbxproj` file open in the Xcode text editor" %} + 1. Find the lines that resemble the following text in the `/* Begin PBXFileReference section */`. @@ -106,7 +106,7 @@ To link the necessary frameworks, follow this procedure. 1. Type `$(PROJECT_DIR)/Flutter/$(CONFIGURATION)/` and press Enter. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/framework-search-paths.png", caption:"Update **Framework Search Paths** in Xcode" %} + After linking the frameworks, they should display in the **Frameworks, Libraries, and Embedded Content** @@ -121,7 +121,7 @@ To embed your dynamic frameworks, complete the following procedure. 1. Click on each of your dynamic frameworks and select **Embed & Sign**. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/choose-to-embed.png", caption:"Select **Embed & Sign** for each of your frameworks in Xcode" %} + Don't include any static frameworks, including `FlutterPluginRegistrant.xcframework`. @@ -131,7 +131,7 @@ To embed your dynamic frameworks, complete the following procedure. 1. Expand **Embed Frameworks**. Your dynamic frameworks should display in that section. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/embed-xcode.png", caption:"The expanded **Embed Frameworks** build phase in Xcode" %} + 1. Build the project. diff --git a/src/_includes/docs/app-figure.md b/src/_includes/docs/app-figure.md deleted file mode 100644 index ffe426a74ec..00000000000 --- a/src/_includes/docs/app-figure.md +++ /dev/null @@ -1,21 +0,0 @@ -{% assign alt = alt | default: caption -%} -{% assign caption = caption | default: '' -%} -{% if width -%} -{% assign width = 'width: ' | append: width | append: ';' -%} -{% else -%} -{% assign width = '' -%} -{% endif -%} -{% if height -%} -{% assign height = 'height: ' | append: height | append: ';' -%} -{% else -%} -{% assign height = '' -%} -{% endif -%} - -
-
- {{alt | escape}} - {% if caption and caption != '' -%} -
{{caption}}
- {% endif -%} -
-
diff --git a/src/_includes/docs/captioned-image.liquid b/src/_includes/docs/captioned-image.liquid deleted file mode 100644 index 02b96113839..00000000000 --- a/src/_includes/docs/captioned-image.liquid +++ /dev/null @@ -1 +0,0 @@ -{{alt | default: caption}}{{caption}} diff --git a/src/_includes/docs/catalog-page-material.md b/src/_includes/docs/catalog-page-material.md deleted file mode 100644 index 8480cfe8d3e..00000000000 --- a/src/_includes/docs/catalog-page-material.md +++ /dev/null @@ -1,31 +0,0 @@ -{% assign category = catalog.index | find: "name", categoryName %} - -{% if category.subcategories -%} -{% for sub in category.subcategories -%} -{% assign components = catalog.widgets | filterByProperty: "subcategories", sub.name, true %} -{% if components.size != 0 -%} - -## {{sub.name}} - - - -{% endif -%} -{% endfor -%} -{% endif -%} diff --git a/src/_includes/docs/catalog-page.md b/src/_includes/docs/catalog-page.md deleted file mode 100644 index 48162ef3355..00000000000 --- a/src/_includes/docs/catalog-page.md +++ /dev/null @@ -1,62 +0,0 @@ -{% assign category = catalog.index | find: "name", categoryName %} - -{{category.description}} - -{% assign components = catalog.widgets | filterByProperty: "categories", categoryName, true %} -{% if components.size != 0 -%} - -{% endif -%} - -{% if category.subcategories and category.subcategories.size != 0 -%} -{% for sub in category.subcategories -%} - {% assign components = catalog.widgets | filterByProperty: "subcategories", sub.name, true %} - {% if components.size != 0 -%} - - ## {{sub.name}} - - - {% endif -%} -{% endfor -%} -{% endif %} - -Find more widgets in the [widget catalog](/ui/widgets). diff --git a/src/_includes/docs/cookbook-group-index.md b/src/_includes/docs/cookbook-group-index.md deleted file mode 100644 index 6007bd0b8c3..00000000000 --- a/src/_includes/docs/cookbook-group-index.md +++ /dev/null @@ -1,6 +0,0 @@ -{% assign pathBase = page.url %} -{% assign recipes = collections.all | childPagesOf: pathBase | sort: 'title' %} - -{% for recipe in recipes -%} -- [{{ recipe.data.title }}]({{ recipe.url }}) -{% endfor -%} diff --git a/src/_includes/docs/debug/debug-flow-android.md b/src/_includes/docs/debug/debug-flow-android.md index 90b662dab59..173d7a21a6d 100644 --- a/src/_includes/docs/debug/debug-flow-android.md +++ b/src/_includes/docs/debug/debug-flow-android.md @@ -13,29 +13,29 @@ Running Gradle task 'bundleDebug'... 27.1s ``` -{% tabs %} -{% tab "Start from VS Code" %} + + #### Start debugging with VS Code first {:#from-vscode-to-android-studio} If you use VS Code to debug most of your code, start with this section. -{% render docs/debug/debug-flow-vscode-as-start.md %} +{% render "docs/debug/debug-flow-vscode-as-start.md" %} #### Attach to the Flutter process in Android Studio -{% render docs/debug/debug-android-attach-process.md %} +{% render "docs/debug/debug-android-attach-process.md" %} -{% endtab %} -{% tab "Start from Android Studio" %} + + #### Start debugging with Android Studio first {:#from-android-studio} If you use Android Studio to debug most of your code, start with this section. -{% render docs/debug/debug-flow-androidstudio-as-start.md %} +{% render "docs/debug/debug-flow-androidstudio-as-start.md" %} -{% render docs/debug/debug-android-attach-process.md %} +{% render "docs/debug/debug-android-attach-process.md" %} -{% endtab %} -{% endtabs %} + + diff --git a/src/_includes/docs/debug/debug-flow-ios.md b/src/_includes/docs/debug/debug-flow-ios.md index 63d328ba51f..f9dd2507029 100644 --- a/src/_includes/docs/debug/debug-flow-ios.md +++ b/src/_includes/docs/debug/debug-flow-ios.md @@ -12,8 +12,8 @@ Warning: Building for device with codesigning disabled. You will have to manuall Building com.example.myApp for device (ios)... ``` -{% tabs "darwin-debug-flow" %} -{% tab "Start from VS Code" %} + + #### Start debugging with VS Code first {:#vscode-ios} @@ -21,7 +21,7 @@ If you use VS Code to debug most of your code, start with this section. ##### Start the Dart debugger in VS Code -{% render docs/debug/debug-flow-vscode-as-start.md, add: add %} +{% render "docs/debug/debug-flow-vscode-as-start.md", add: add %} ##### Attach to the Flutter process in Xcode @@ -33,8 +33,8 @@ To attach to the Flutter app in Xcode: 1. Select **Runner**. It should be at the top of the **Attach to Process** menu under the **Likely Targets** heading. -{% endtab %} -{% tab "Start from Xcode" %} + + #### Start debugging with Xcode first {:#xcode-ios} @@ -62,9 +62,9 @@ If you use Xcode to debug most of your code, start with this section. {% comment %} ![Start button in Xcode interface](/assets/images/docs/testing/debugging/native/xcode/run-app.png)
- + Start button displayed in Xcode interface. - +
{% endcomment %} @@ -102,5 +102,5 @@ If you use Xcode to debug most of your code, start with this section. ![Alt text](/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri-filled.png) {% endcomment %} -{% endtab %} -{% endtabs %} +
+
diff --git a/src/_includes/docs/debug/debug-flow-macos.md b/src/_includes/docs/debug/debug-flow-macos.md index 8e8c34202c8..aec1d722e6b 100644 --- a/src/_includes/docs/debug/debug-flow-macos.md +++ b/src/_includes/docs/debug/debug-flow-macos.md @@ -11,14 +11,14 @@ flutter build macos --debug Building macOS application... ``` -{% tabs "darwin-debug-flow" %} -{% tab "Start from VS Code" %} + + #### Start debugging with VS Code first {:#vscode-macos} ##### Start the debugger in VS Code -{% render docs/debug/debug-flow-vscode-as-start.md %} +{% render "docs/debug/debug-flow-vscode-as-start.md" %} ##### Attach to the Flutter process in Xcode @@ -30,8 +30,8 @@ Building macOS application... **Runner** should be at the top of the **Attach to Process** menu under the **Likely Targets** heading. -{% endtab %} -{% tab "Start from Xcode" %} + + #### Start debugging with Xcode first {:#xcode-macos} @@ -82,5 +82,5 @@ Building macOS application... ![Alt text](/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri-filled.png) {% endcomment %} -{% endtab %} -{% endtabs %} + + diff --git a/src/_includes/docs/debug/debug-flow-vscode-as-start.md b/src/_includes/docs/debug/debug-flow-vscode-as-start.md index da8ffbda77b..6612a788a46 100644 --- a/src/_includes/docs/debug/debug-flow-vscode-as-start.md +++ b/src/_includes/docs/debug/debug-flow-vscode-as-start.md @@ -36,5 +36,5 @@ This button only works for iOS or Android. Desktop apps launch a browser. {% if add == 'launch' -%} -{% render docs/debug/vscode-flutter-attach-json.md %} +{% render "docs/debug/vscode-flutter-attach-json.md" %} {% endif -%} diff --git a/src/_includes/docs/debug/debug-flow-windows.md b/src/_includes/docs/debug/debug-flow-windows.md index ff78c8192bd..7210dd6dc96 100644 --- a/src/_includes/docs/debug/debug-flow-windows.md +++ b/src/_includes/docs/debug/debug-flow-windows.md @@ -12,8 +12,8 @@ Building Windows application... 31.4s √ Built build\windows\runner\Debug\my_app.exe. ``` -{% tabs %} -{% tab "Start from VS Code" %} + + #### Start debugging with VS Code first {:#vscode-windows} @@ -21,12 +21,12 @@ If you use VS Code to debug most of your code, start with this section. ##### Start the debugger in VS Code -{% render docs/debug/debug-flow-vscode-as-start.md %} +{% render "docs/debug/debug-flow-vscode-as-start.md" %} {% comment %} !['Flutter app generated as a Windows app. The app displays two buttons to open this page in a browser or in the app'](/assets/images/docs/testing/debugging/native/url-launcher-app/windows.png){:width="50%"}
- + Flutter app generated as a Windows app. The app displays two buttons to open this page in a browser or in the app.
@@ -69,8 +69,8 @@ If you use VS Code to debug most of your code, start with this section. ![Visual Studio debugger running and monitoring the Flutter app](/assets/images/docs/testing/debugging/native/visual-studio/debugger-active.png){:width="100%"} {% endcomment %} -{% endtab %} -{% tab "Start from Visual Studio" %} +
+ #### Start debugging with Visual Studio first @@ -137,5 +137,5 @@ If you use Visual Studio to debug most of your code, start with this section. ![Alt text](/assets/images/docs/testing/debugging/vscode-ui/screens/vscode-add-attach-uri-filled.png) {% endcomment %} -{% endtab %} -{% endtabs %} + +
diff --git a/src/_includes/docs/learning-resources-index/grid.md b/src/_includes/docs/learning-resources-index/grid.md deleted file mode 100644 index 2c2405b7338..00000000000 --- a/src/_includes/docs/learning-resources-index/grid.md +++ /dev/null @@ -1,65 +0,0 @@ -
- {%- for item in resources -%} - - {%- if item.imageUrl -%} -
- -
- {%- endif -%} -
- {%- liquid - case item.type - when 'codelab' - assign pill-color = 'flutter-blue' - when 'workshop' - assign pill-color = 'flutter-blue' - when 'quickstart' - assign pill-color = 'purple' - when 'demo' - assign pill-color = 'purple' - else - assign pill-color = 'teal' - endcase -%} - {{ item.type | capitalize }} - {%- if item.link.label == "Flutter Github" -%} - - - - {%- elsif item.link.label == 'Dart Github' -%} - Dart logo - {%- elsif item.link.label == 'Flutter docs' -%} - Flutter logo - {%- elsif item.link.label == 'Dart docs' -%} - Dart icon - {%- elsif item.link.label == "Google Codelab" -%} - - - - {%- elsif item.link.label == "YouTube" -%} - - - - {%- elsif item.link.label == "Medium" -%} - - - - {%- endif -%} -
-
- {{ item.name }} -
-
- - {{ item.description }} - -
-
- {%- endfor -%} -
diff --git a/src/_includes/docs/learning-resources-index/side-filters.liquid b/src/_includes/docs/learning-resources-index/side-filters.liquid deleted file mode 100644 index 4692a136a93..00000000000 --- a/src/_includes/docs/learning-resources-index/side-filters.liquid +++ /dev/null @@ -1,43 +0,0 @@ - -
-
-
- -
-
Filter by
-
-

Subject

- - -

Type

-
    - {% for filter in filters.type -%} -
  • - - -
  • - {% endfor -%} -
-
-
-
diff --git a/src/_includes/docs/release/archive-release.md b/src/_includes/docs/release/archive-release.md deleted file mode 100644 index 1f3cde1af25..00000000000 --- a/src/_includes/docs/release/archive-release.md +++ /dev/null @@ -1,11 +0,0 @@ -{% assign os = os | downcase -%} -{% assign channel = channel | downcase -%} - -Select from the following scrollable list: - -
- - - -
Flutter versionArchitectureRefRelease DateDart versionProvenance
Loading...
-
diff --git a/src/_includes/docs/swift-package-manager/migrate-ios-project-manually.md b/src/_includes/docs/swift-package-manager/migrate-ios-project-manually.md index fd99169deac..f9f71a3ed42 100644 --- a/src/_includes/docs/swift-package-manager/migrate-ios-project-manually.md +++ b/src/_includes/docs/swift-package-manager/migrate-ios-project-manually.md @@ -22,20 +22,20 @@ the following files in your issue: 1. Open your app (`ios/Runner.xcworkspace`) in Xcode. 1. Navigate to **Package Dependencies** for the project. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/package-dependencies.png", caption:"The project's package dependencies" %} + 1. Click add. 1. In the dialog that opens, click **Add Local...**. 1. Navigate to `ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage` and click **Add Package**. 1. Ensure that it's added to the `Runner` target and click **Add Package**. - - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/choose-package-products.png", caption:"Ensure that the package is added to the `Runner` target" %} + + 1. Ensure that `FlutterGeneratedPluginSwiftPackage` was added to **Frameworks, Libraries, and Embedded Content**. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/add-generated-framework.png", caption:"Ensure that `FlutterGeneratedPluginSwiftPackage` was added to **Frameworks, Libraries, and Embedded Content**" %} + ### Step 2: Add Run Prepare Flutter Framework Script Pre-Action {:.no_toc} @@ -59,7 +59,7 @@ the following files in your issue: "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ``` - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/add-flutter-pre-action.png", caption:"Add **Run Prepare Flutter Framework Script** build pre-action" %} + ### Step 3: Run app {:.no_toc} @@ -67,7 +67,7 @@ the following files in your issue: 1. Ensure that **Run Prepare Flutter Framework Script** runs as a pre-action and that `FlutterGeneratedPluginSwiftPackage` is a target dependency. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/flutter-pre-action-build-log.png", caption:"Ensure **Run Prepare Flutter Framework Script** runs as a pre-action" %} + 1. Ensure that the app runs on the command line with `flutter run`. diff --git a/src/_includes/docs/swift-package-manager/migrate-ios-project.md b/src/_includes/docs/swift-package-manager/migrate-ios-project.md index 4c73d07b924..a038c54dfdc 100644 --- a/src/_includes/docs/swift-package-manager/migrate-ios-project.md +++ b/src/_includes/docs/swift-package-manager/migrate-ios-project.md @@ -30,7 +30,7 @@ To migrate your project: 1. Ensure that **Run Prepare Flutter Framework Script** runs as a pre-action and that `FlutterGeneratedPluginSwiftPackage` is a target dependency. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/flutter-pre-action-build-log.png", caption:"Ensure **Run Prepare Flutter Framework Script** runs as a pre-action" %} + [Turn on Swift Package Manager]: /packages-and-plugins/swift-package-manager/for-app-developers/#how-to-turn-on-swift-package-manager [manualIntegration]: /packages-and-plugins/swift-package-manager/for-app-developers/#add-to-a-flutter-app-manually diff --git a/src/_includes/docs/swift-package-manager/migrate-macos-project-manually.md b/src/_includes/docs/swift-package-manager/migrate-macos-project-manually.md index 1ae5bfa8ef6..b639ad1acf5 100644 --- a/src/_includes/docs/swift-package-manager/migrate-macos-project-manually.md +++ b/src/_includes/docs/swift-package-manager/migrate-macos-project-manually.md @@ -22,7 +22,7 @@ the following files in your issue: 1. Open your app (`macos/Runner.xcworkspace`) in Xcode. 1. Navigate to **Package Dependencies** for the project. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/package-dependencies.png", caption:"The project's package dependencies" %} + 1. Click add. 1. In the dialog that opens, click the **Add Local...**. @@ -30,12 +30,12 @@ the following files in your issue: and click the **Add Package**. 1. Ensure that it's added to the Runner Target and click **Add Package**. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/choose-package-products.png", caption:"Ensure that the package is added to the `Runner` target" %} + 1. Ensure that `FlutterGeneratedPluginSwiftPackage` was added to **Frameworks, Libraries, and Embedded Content**. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/add-generated-framework.png", caption:"Ensure that `FlutterGeneratedPluginSwiftPackage` was added to **Frameworks, Libraries, and Embedded Content**" %} + ### Step 2: Add Run Prepare Flutter Framework Script Pre-Action {:.no_toc} @@ -59,7 +59,7 @@ the following files in your issue: "$FLUTTER_ROOT"/packages/flutter_tools/bin/macos_assemble.sh prepare ``` - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/add-flutter-pre-action.png", caption:"Add **Run Prepare Flutter Framework Script** build pre-action" %} + ### Step 3: Run app {:.no_toc} @@ -67,7 +67,7 @@ the following files in your issue: 1. Ensure that **Run Prepare Flutter Framework Script** runs as a pre-action and that `FlutterGeneratedPluginSwiftPackage` is a target dependency. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/flutter-pre-action-build-log.png", caption:"Ensure `Run Prepare Flutter Framework Script` runs as a pre-action" %} + 1. Ensure that the app runs on the command line with `flutter run`. diff --git a/src/_includes/docs/swift-package-manager/migrate-macos-project.md b/src/_includes/docs/swift-package-manager/migrate-macos-project.md index 06d005902cd..6aeeb1c9a63 100644 --- a/src/_includes/docs/swift-package-manager/migrate-macos-project.md +++ b/src/_includes/docs/swift-package-manager/migrate-macos-project.md @@ -30,7 +30,7 @@ To migrate your project: 1. Ensure that **Run Prepare Flutter Framework Script** runs as a pre-action and that `FlutterGeneratedPluginSwiftPackage` is a target dependency. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/flutter-pre-action-build-log.png", caption:"Ensure **Run Prepare Flutter Framework Script** runs as a pre-action" %} + [Turn on Swift Package Manager]: /packages-and-plugins/swift-package-manager/for-app-developers/#how-to-turn-on-swift-package-manager -[manualIntegration]: /packages-and-plugins/swift-package-manager/for-app-developers/#add-to-a-flutter-app-manually \ No newline at end of file +[manualIntegration]: /packages-and-plugins/swift-package-manager/for-app-developers/#add-to-a-flutter-app-manually diff --git a/src/_includes/docs/test/integration/windows-example.md b/src/_includes/docs/test/integration/windows-example.md index 4b2a527dcd6..90ff81ef6df 100644 --- a/src/_includes/docs/test/integration/windows-example.md +++ b/src/_includes/docs/test/integration/windows-example.md @@ -1,4 +1,4 @@ -```powershell +```ps PS C:\path\to\counter_app> flutter test .\integration_test\app_test.dart Resolving dependencies... Downloading packages... diff --git a/src/_includes/docs/testing-toc.md b/src/_includes/docs/testing-toc.md deleted file mode 100644 index 7834381d7d9..00000000000 --- a/src/_includes/docs/testing-toc.md +++ /dev/null @@ -1,18 +0,0 @@ -{% comment %} - Generates a list of testing recipes for the given type. The type - corresponds to the name of the directory under cookbook/testing/*. - - Usage: {% include docs/testing_toc.md type='unit' %} -{% endcomment -%} -{% assign dir = 'cookbook/testing/' | append: include.type -%} -{% assign recipes = collections.all | childPagesOf: dir | sort: 'title' %} - -{% for recipe in recipes -%} -{% comment -%} - Omit the index page for the given type -{% endcomment -%} -{% assign frag = recipe.url | split: '/' | last %} -{% if frag != include.type -%} -- [{{ recipe.data.title }}]({{ recipe.url }}) -{% endif -%} -{% endfor %} \ No newline at end of file diff --git a/src/_includes/expansion-list.html b/src/_includes/expansion-list.html deleted file mode 100644 index 9b28b86d34d..00000000000 --- a/src/_includes/expansion-list.html +++ /dev/null @@ -1,60 +0,0 @@ -{%- comment -%} -This component expects a list of article or page objects. -The frontmatter of each article should have the following attributes: -- title: String - name of the article -- description: String - 1-2 sentence description of the article -- contentTags: List - A short list of items that describe what the reader - can expect from the content or describe meta information about the article. - i.e. data, user-experience OR tutorial, 10 minute read -- iconPath: String - the path to an image that is shown in next to the title -{%- endcomment -%} - -
- {% for item in list -%} - {% assign id = baseId | append: '-expansion-' | append: forloop.index -%} - {% if item.expanded -%} - {% assign expanded = 'true' -%} - {% assign show = 'show' -%} - {% else -%} - {% assign class = 'collapsed' -%} - {% assign expanded = 'false' -%} - {% assign show = '' -%} - {% endif -%} - - {%- endfor -%} -
diff --git a/src/_includes/footer.html b/src/_includes/footer.html deleted file mode 100644 index 71247a0f595..00000000000 --- a/src/_includes/footer.html +++ /dev/null @@ -1,40 +0,0 @@ - diff --git a/src/_includes/header.html b/src/_includes/header.html deleted file mode 100644 index f7d12ab622e..00000000000 --- a/src/_includes/header.html +++ /dev/null @@ -1,102 +0,0 @@ - diff --git a/src/_includes/next-prev-nav.html b/src/_includes/next-prev-nav.html deleted file mode 100644 index d948351e0e9..00000000000 --- a/src/_includes/next-prev-nav.html +++ /dev/null @@ -1,22 +0,0 @@ -{% if next or prev -%} - -{% endif -%} diff --git a/src/_includes/side-toc.html b/src/_includes/side-toc.html deleted file mode 100644 index 6ba13640ae5..00000000000 --- a/src/_includes/side-toc.html +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/src/_includes/sidenav-level-1.html b/src/_includes/sidenav-level-1.html deleted file mode 100644 index ed3aa98b3bd..00000000000 --- a/src/_includes/sidenav-level-1.html +++ /dev/null @@ -1,63 +0,0 @@ -{% assign pageUrlPath = url | regexReplace: '/index$|/index\.html$|\.html$|/$' -%} -{% assign activeEntries = pageUrlPath | activeNavForPage: activeNav -%} - - diff --git a/src/_includes/sidenav-level-2.html b/src/_includes/sidenav-level-2.html deleted file mode 100644 index 09a594a0536..00000000000 --- a/src/_includes/sidenav-level-2.html +++ /dev/null @@ -1,68 +0,0 @@ -{% for entry in children -%} - -{% if activeEntries and forloop.index == activeEntries[1] -%} - {% assign isActive = true -%} - {% assign class = 'nav-link active' -%} -{% else -%} - {% assign isActive = false -%} - {% assign class = 'nav-link' -%} -{% endif -%} - - -{% if entry == 'divider' -%} - -{% elsif entry.header -%} - -{%- elsif entry.children -%} - - {% assign class = class | append: ' collapsible' -%} - - {% if isActive or entry.expanded -%} - {% assign expanded = 'true' -%} - {% assign show = 'show' -%} - {% else -%} - {% assign class = class | append: ' collapsed' -%} - {% assign expanded = 'false' -%} - {% assign show = '' -%} - {% endif -%} - - {% assign id = parentId | append: '-' | append: forloop.index -%} - {% assign href = entry.permalink -%} - {% unless href -%} - {% assign href = '#' | append: id -%} - {% endunless -%} - - -{%- elsif entry.permalink -%} - {% if entry.permalink contains '://' -%} - {% assign isExternal = true -%} - {% else -%} - {% assign isExternal = false -%} - {% endif -%} - - - -{% endif -%} -{% endfor %} diff --git a/src/_includes/sidenav-level-3.html b/src/_includes/sidenav-level-3.html deleted file mode 100644 index fa9c6909fc8..00000000000 --- a/src/_includes/sidenav-level-3.html +++ /dev/null @@ -1,63 +0,0 @@ -{% for entry in children -%} - -{% if activeEntries and forloop.index == activeEntries[2] -%} - {% assign isActive = true -%} - {% assign class = 'nav-link active' -%} -{% else -%} - {% assign isActive = false -%} - {% assign class = 'nav-link' -%} -{% endif -%} - -{% if entry == 'divider' -%} - -{%- elsif entry.children -%} - {% assign class = class | append: ' collapsible' -%} - - {% if isActive or entry.expanded -%} - {% assign expanded = 'true' -%} - {% assign show = 'show' -%} - {% else -%} - {% assign class = class | append: ' collapsed' -%} - {% assign expanded = 'false' -%} - {% assign show = '' -%} - {% endif -%} - - {% assign id = parentId | append: '-' | append: forloop.index -%} - {% assign href = entry.permalink -%} - {% unless href -%} - {% assign href = '#' | append: id -%} - {% endunless -%} - - -{%- elsif entry.permalink -%} - {% if entry.permalink contains '://' -%} - {% assign isExternal = true -%} - {% else -%} - {% assign isExternal = false -%} - {% endif -%} - - - -{% endif -%} -{% endfor -%} diff --git a/src/_includes/sidenav-level-4.html b/src/_includes/sidenav-level-4.html deleted file mode 100644 index 975eea3d91d..00000000000 --- a/src/_includes/sidenav-level-4.html +++ /dev/null @@ -1,28 +0,0 @@ -{% for entry in children -%} - {% if entry.permalink -%} - - {% if activeEntries and forloop.index == activeEntries[3] -%} - {% assign isActive = true -%} - {% assign class = 'nav-link active' -%} - {% else -%} - {% assign isActive = false -%} - {% assign class = 'nav-link' -%} - {% endif -%} - - {% if entry.permalink contains '://' -%} - {% assign isExternal = true -%} - {% else -%} - {% assign isExternal = false -%} - {% endif -%} - - - {% endif -%} -{% endfor -%} diff --git a/src/_includes/toc-contents.html b/src/_includes/toc-contents.html deleted file mode 100644 index 4f9d113e3fa..00000000000 --- a/src/_includes/toc-contents.html +++ /dev/null @@ -1,16 +0,0 @@ -
    - {% for topLevel in tocContents.toc %} -
  • - {{topLevel.text}} - {% if topLevel.children and topLevel.children.size > 0 %} -
      - {% for child in topLevel.children %} -
    • - {{child.text}} -
    • - {% endfor -%} -
    - {% endif -%} -
  • - {% endfor -%} -
diff --git a/src/_includes/top-toc.html b/src/_includes/top-toc.html deleted file mode 100644 index 2832fa1bd27..00000000000 --- a/src/_includes/top-toc.html +++ /dev/null @@ -1,26 +0,0 @@ - diff --git a/src/_includes/trailing.html b/src/_includes/trailing.html deleted file mode 100644 index 63249b13ada..00000000000 --- a/src/_includes/trailing.html +++ /dev/null @@ -1,40 +0,0 @@ -{% assign repo = repo | default: site.repo.this -%} -{% capture pageSource -%} {{repo}}/tree/{{site.branch}}/{{page.inputPath | replace: './', ''}} {%- endcapture -%} -{% assign url = site.url | append: page.url -%} - -
-
- - - -
- - -
diff --git a/src/_layouts/base.html b/src/_layouts/base.html deleted file mode 100644 index 6ee0c11e7cf..00000000000 --- a/src/_layouts/base.html +++ /dev/null @@ -1,132 +0,0 @@ -{% assign cacheBust = '?v=7' %} -{% assign pageUrl = page.url | regexReplace: '/index$|/index.html$|\.html$|/$' -%} - - - - - - {% if shortTitle %}{{shortTitle}}{% else %}{{title}}{% endif %} | {{site.title}} - - - - - {% if noindex -%} - - {% endif -%} - - {% unless strip_fonts == true -%} - - - {% endunless -%} - - {%- if isProduction == true -%} - - - - - {% endif -%} - - {% assign desc = description | default: site.description | strip_html | strip_newlines | truncate: 160 -%} - {% unless desc and desc != '' -%} - {% assign error = pageUrl | append: ' must have a description specified!' -%} - {{ error | throwError }} - {% endunless %} - - {% assign ogImagePath = image.path | default: layout.image.path | default: site.defaultShareImage -%} - - - - - - - - - - - {% unless strip_fonts == true -%} - - - - - {% endunless -%} - - - - - {% if css -%} - {% for cssFile in css -%} - - {% endfor -%} - {% endif -%} - - - - {% render cookie-notice.html %} - - {%- if isProduction == true -%} - - {% endif -%} - - {% include header.html %} - -
- - {{ content }} - - {% render footer.html %} - -
- - {% comment %} - This script is used to set the theme based on the user's - previously selected theme. - It is inline in the HTML to avoid theme flashing. - {% endcomment %} - - - - - - {% if js -%} - {% for jsFile in js -%} - - {% endfor -%} - {% endif -%} - - - - \ No newline at end of file diff --git a/src/_layouts/blank.html b/src/_layouts/blank.html deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/_layouts/default.html b/src/_layouts/default.html deleted file mode 100644 index f7e094c6d96..00000000000 --- a/src/_layouts/default.html +++ /dev/null @@ -1,47 +0,0 @@ ---- -layout: base ---- - -{% if showToc != false -%} -{% assign tocContents = content | generateToc %} -{% if tocContents == null or tocContents == '' or tocContents.count < 2 -%} -{% assign showToc = false %} -{% endif -%} -{% endif -%} - -
-
- {% render sidenav-level-1.html, url:page.url, nav:sidenav, activeNav:activeNav %} -
- -
- {% if showToc != false -%} - {% render top-toc.html, tocContents:tocContents, title:title %} - {% endif -%} - {%- if site.showBanner and showBanner != false -%} - - {% endif -%} -
- {% if showToc != false -%} - - {% endif -%} -
- - {{ content }} - - {% render next-prev-nav.html, prev:prev, next:next %} - - {% include trailing.html %} -
-
-
-
diff --git a/src/_layouts/none.liquid b/src/_layouts/none.liquid deleted file mode 100644 index b92f6522338..00000000000 --- a/src/_layouts/none.liquid +++ /dev/null @@ -1 +0,0 @@ -{{content}} diff --git a/src/_layouts/toc.md b/src/_layouts/toc.md deleted file mode 100644 index 7aaf6c259f7..00000000000 --- a/src/_layouts/toc.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -layout: default -showToc: false -sitemap: false ---- - -{% assign url = page.url | regexReplace: '/index$|/index.html$|/$' -%} -{% assign pathParts = url | split: '/' -%} -{% assign topics = sidenav -%} -{% assign path = '' -%} - -{% comment %} - - pathParts[0] == '' because page.url always starts with '/' -{% endcomment -%} - -{% for pathPart in pathParts -%} - {% if forloop.first == true -%} - {% assign path = '' -%} - {% else -%} - {% assign path = path | append: '/' | append: pathPart -%} - {% endif -%} - {% if forloop.index0 > 0 and path != '/ui' -%} - {% assign topics = topics | where: "permalink", path -%} - {% assign topics = topics[0].children | where: "title" -%} - {% endif -%} -{% endfor -%} - -{% if topics -%} -### Topics - -{% for topic in topics -%} - -{% if topic.permalink == nil -%} -{% if topic contains 'header' %} -#### {{topic.header}} - -{% else -%} - - {{topic.title}} -{% endif -%} -{% else -%} - - [{{topic.title}}]({{topic.permalink}}) -{% endif -%} -{% endfor %} -{% endif -%} - -{{content}} diff --git a/src/_sass/components/_dropdown.scss b/src/_sass/components/_dropdown.scss deleted file mode 100644 index 797a7a3b83f..00000000000 --- a/src/_sass/components/_dropdown.scss +++ /dev/null @@ -1,60 +0,0 @@ -@use '../base/mixins'; - -.dropdown-content { - display: none; - position: absolute; - background-color: var(--site-header-bgColor); - box-shadow: 0 6px 18px 0 rgba(0, 0, 0, 0.2); - border-radius: 0.4rem; - width: max-content; - border: var(--site-outline-variant) 1px solid; - z-index: var(--site-z-dropdown); - - &.show { - display: block; - } - - .dropdown-divider { - background-color: var(--site-outline-variant); - border-radius: 0.5rem; - height: 0.125rem; - margin: 0.25rem; - padding: 0 !important; - } - - .dropdown-menu { - padding: 0.2rem; - - ul { - display: flex; - flex-direction: column; - list-style: none; - padding: 0; - margin: 0; - - li { - padding: 0.25rem; - - a, button { - display: flex; - align-items: center; - flex-direction: row; - width: 100%; - gap: 0.4rem; - padding: 0.2rem 0.4rem; - border-radius: var(--site-radius); - - text-decoration: none; - - &:hover { - @include mixins.interaction-style(4%); - } - - &:active { - @include mixins.interaction-style(6%); - } - } - } - } - } -} diff --git a/src/_sass/components/_theming.scss b/src/_sass/components/_theming.scss deleted file mode 100644 index a0273c3ea93..00000000000 --- a/src/_sass/components/_theming.scss +++ /dev/null @@ -1,29 +0,0 @@ -#theme-switcher { - position: relative; - - > .dropdown-content { - right: -0.5rem; - - .material-symbols { - font-size: 20px; - } - } - - @at-root body:not(.dark-mode):not(.auto-mode) & { - button[data-theme="light"] { - background-color: var(--site-primary-color-highlight); - } - } - - @at-root body.dark-mode:not(.auto-mode) & { - button[data-theme="dark"] { - background-color: var(--site-primary-color-highlight); - } - } - - @at-root body.auto-mode & { - button[data-theme="auto"] { - background-color: var(--site-primary-color-highlight); - } - } -} diff --git a/src/content/.eleventyignore b/src/content/.eleventyignore deleted file mode 100644 index e13cb19f324..00000000000 --- a/src/content/.eleventyignore +++ /dev/null @@ -1,5 +0,0 @@ -**/README.md -**/_shared -**/_* -**/release-notes-*-src.md -**/breaking-changes/template.md diff --git a/src/content/404.html b/src/content/404.html index 777e5d76570..8348e197f23 100644 --- a/src/content/404.html +++ b/src/content/404.html @@ -2,9 +2,7 @@ title: Sorry, we couldn't find that page... shortTitle: Page not found description: Page not found -layout: default -extraBodyClass: site-not-found -permalink: /404.html +bodyClass: site-not-found sitemap: false showToc: false showBreadcrumbs: false diff --git a/src/content/add-to-app/android/_initial-route-cached-engine.md b/src/content/add-to-app/android/_initial-route-cached-engine.md index ec46e8eb2a1..18ddb766a44 100644 --- a/src/content/add-to-app/android/_initial-route-cached-engine.md +++ b/src/content/add-to-app/android/_initial-route-cached-engine.md @@ -12,8 +12,8 @@ with a custom initial route can configure their cached executing the Dart entrypoint. The following example demonstrates the use of an initial route with a cached engine: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyApplication.kt" class MyApplication : Application() { @@ -36,8 +36,8 @@ class MyApplication : Application() { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyApplication.java" public class MyApplication extends Application { @@ -60,8 +60,8 @@ public class MyApplication extends Application { } ``` -{% endtab %} -{% endtabs %} + + By setting the initial route of the navigation channel, the associated `FlutterEngine` displays the desired route upon initial execution of the @@ -73,4 +73,3 @@ Developers who would like to use the same `FlutterEngine` between different `Activity`s and `Fragment`s and switch the route between those displays need to set up a method channel and explicitly instruct their Dart code to change `Navigator` routes. - diff --git a/src/content/add-to-app/android/add-flutter-fragment.md b/src/content/add-to-app/android/add-flutter-fragment.md index a93675e07cc..ae7e280b4fa 100644 --- a/src/content/add-to-app/android/add-flutter-fragment.md +++ b/src/content/add-to-app/android/add-flutter-fragment.md @@ -44,8 +44,8 @@ To add a `FlutterFragment` to a host `Activity`, instantiate and attach an instance of `FlutterFragment` in `onCreate()` within the `Activity`, or at another time that works for your app: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyActivity.kt" class MyActivity : FragmentActivity() { @@ -93,8 +93,8 @@ class MyActivity : FragmentActivity() { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyActivity.java" public class MyActivity extends FragmentActivity { @@ -141,8 +141,8 @@ public class MyActivity extends FragmentActivity { } ``` -{% endtab %} -{% endtabs %} + + The previous code is sufficient to render a Flutter UI that begins with a call to your `main()` Dart entrypoint, @@ -152,8 +152,8 @@ Flutter behavior. Flutter depends on various OS signals that must be forwarded from your host `Activity` to `FlutterFragment`. These calls are shown in the following example: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyActivity.kt" class MyActivity : FragmentActivity() { @@ -206,8 +206,8 @@ class MyActivity : FragmentActivity() { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyActivity.java" public class MyActivity extends FragmentActivity { @@ -267,8 +267,8 @@ public class MyActivity extends FragmentActivity { } ``` -{% endtab %} -{% endtabs %} + + With the OS signals forwarded to Flutter, your `FlutterFragment` works as expected. @@ -291,10 +291,10 @@ using an existing, pre-warmed instance of `FlutterEngine`. To use a pre-warmed `FlutterEngine` in a `FlutterFragment`, instantiate a `FlutterFragment` with the `withCachedEngine()` -factory method. +factory method. -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyApplication.kt" // Somewhere in your app, before your FlutterFragment is needed, @@ -317,8 +317,8 @@ FlutterEngineCache FlutterFragment.withCachedEngine("my_engine_id").build() ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyApplication.java" // Somewhere in your app, before your FlutterFragment is needed, @@ -341,8 +341,8 @@ FlutterEngineCache FlutterFragment.withCachedEngine("my_engine_id").build(); ``` -{% endtab %} -{% endtabs %} + + `FlutterFragment` internally knows about [`FlutterEngineCache`][] and retrieves the pre-warmed `FlutterEngine` based on the ID @@ -354,7 +354,7 @@ first Flutter frame as quickly as possible. #### Initial route with a cached engine -{% render docs/add-to-app/android-initial-route-cached-engine.md %} +{% render "docs/add-to-app/android-initial-route-cached-engine.md" %} ## Display a splash screen @@ -376,8 +376,8 @@ initial routes (routes other than `/`). To facilitate this, `FlutterFragment`'s `Builder` allows you to specify a desired initial route, as shown: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyActivity.kt" // With a new FlutterEngine. @@ -386,8 +386,8 @@ val flutterFragment = FlutterFragment.withNewEngine() .build() ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyActivity.java" // With a new FlutterEngine. @@ -396,8 +396,8 @@ FlutterFragment flutterFragment = FlutterFragment.withNewEngine() .build(); ``` -{% endtab %} -{% endtabs %} + + :::note `FlutterFragment`'s initial route property has no effect when a pre-warmed @@ -417,8 +417,8 @@ Dart entrypoint: `main()`, but you can define other entrypoints. Dart entrypoint to execute for the given Flutter experience. To specify an entrypoint, build `FlutterFragment`, as shown: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyActivity.kt" val flutterFragment = FlutterFragment.withNewEngine() @@ -426,8 +426,8 @@ val flutterFragment = FlutterFragment.withNewEngine() .build() ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyActivity.java" FlutterFragment flutterFragment = FlutterFragment.withNewEngine() @@ -435,8 +435,8 @@ FlutterFragment flutterFragment = FlutterFragment.withNewEngine() .build(); ``` -{% endtab %} -{% endtabs %} + + The `FlutterFragment` configuration results in the execution of a Dart entrypoint called `mySpecialEntrypoint()`. @@ -468,8 +468,8 @@ then you need to use `TextureView` instead of `SurfaceView`. Select a `TextureView` by building a `FlutterFragment` with a `texture` `RenderMode`: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyActivity.kt" // With a new FlutterEngine. @@ -483,8 +483,8 @@ val flutterFragment = FlutterFragment.withCachedEngine("my_engine_id") .build() ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyActivity.java" // With a new FlutterEngine. @@ -498,8 +498,8 @@ FlutterFragment flutterFragment = FlutterFragment.withCachedEngine("my_engine_id .build(); ``` -{% endtab %} -{% endtabs %} + + Using the configuration shown, the resulting `FlutterFragment` renders its UI to a `TextureView`. @@ -536,8 +536,8 @@ for information about controlling the `RenderMode`. To enable transparency for a `FlutterFragment`, build it with the following configuration: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyActivity.kt" // Using a new FlutterEngine. @@ -551,8 +551,8 @@ val flutterFragment = FlutterFragment.withCachedEngine("my_engine_id") .build() ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyActivity.java" // Using a new FlutterEngine. @@ -566,8 +566,8 @@ FlutterFragment flutterFragment = FlutterFragment.withCachedEngine("my_engine_id .build(); ``` -{% endtab %} -{% endtabs %} + + ## The relationship between `FlutterFragment` and its `Activity` @@ -598,8 +598,8 @@ prevent Flutter from controlling the `Activity`'s system UI, use the `shouldAttachEngineToActivity()` method in `FlutterFragment`'s `Builder`, as shown: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyActivity.kt" // Using a new FlutterEngine. @@ -613,8 +613,8 @@ val flutterFragment = FlutterFragment.withCachedEngine("my_engine_id") .build() ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyActivity.java" // Using a new FlutterEngine. @@ -628,8 +628,8 @@ FlutterFragment flutterFragment = FlutterFragment.withCachedEngine("my_engine_id .build(); ``` -{% endtab %} -{% endtabs %} + + Passing `false` to the `shouldAttachEngineToActivity()` `Builder` method prevents Flutter from interacting with diff --git a/src/content/add-to-app/android/add-flutter-screen.md b/src/content/add-to-app/android/add-flutter-screen.md index d87912a4e11..d6e0a61f8f4 100644 --- a/src/content/add-to-app/android/add-flutter-screen.md +++ b/src/content/add-to-app/android/add-flutter-screen.md @@ -54,8 +54,8 @@ import io.flutter.embedding.android.FlutterActivity; ``` ::: -{% tabs "android-language" %} -{% tab "Jetpack Compose" %} + + ```kotlin title="ExistingActivity.kt" MyButton(onClick = { @@ -72,8 +72,8 @@ fun MyButton(onClick: () -> Unit) { } ``` -{% endtab %} -{% tab "Kotlin" %} + + ```kotlin title="ExistingActivity.kt" myButton.setOnClickListener { @@ -83,8 +83,8 @@ myButton.setOnClickListener { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="ExistingActivity.java" myButton.setOnClickListener(new OnClickListener() { @@ -97,8 +97,8 @@ myButton.setOnClickListener(new OnClickListener() { }); ``` -{% endtab %} -{% endtabs %} + + The previous example assumes that your Dart entrypoint is called `main()`, and your initial Flutter route is '/'. @@ -108,8 +108,8 @@ The following example demonstrates how to launch a `FlutterActivity` that initially renders a custom route in Flutter. -{% tabs "android-language" %} -{% tab "Jetpack Compose" %} + + ```kotlin title="ExistingActivity.kt" MyButton(onClick = { @@ -129,8 +129,8 @@ fun MyButton(onClick: () -> Unit) { } ``` -{% endtab %} -{% tab "Kotlin" %} + + ```kotlin title="ExistingActivity.kt" myButton.setOnClickListener { @@ -143,8 +143,8 @@ myButton.setOnClickListener { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="ExistingActivity.java" myButton.addOnClickListener(new OnClickListener() { @@ -160,8 +160,8 @@ myButton.addOnClickListener(new OnClickListener() { }); ``` -{% endtab %} -{% endtabs %} + + Replace `"/my_route"` with your desired initial route. @@ -189,8 +189,8 @@ location in your app to instantiate a `FlutterEngine`. The following example arbitrarily pre-warms a `FlutterEngine` in the `Application` class: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyApplication.kt" class MyApplication : Application() { @@ -215,13 +215,13 @@ class MyApplication : Application() { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MyApplication.java" public class MyApplication extends Application { public FlutterEngine flutterEngine; - + @Override public void onCreate() { super.onCreate(); @@ -241,8 +241,8 @@ public class MyApplication extends Application { } ``` -{% endtab %} -{% endtabs %} + + The ID passed to the [`FlutterEngineCache`][] can be whatever you want. Make sure that you pass the same ID to any `FlutterActivity` @@ -270,8 +270,8 @@ to instruct your `FlutterActivity` to use the cached To accomplish this, use `FlutterActivity`'s `withCachedEngine()` builder: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="ExistingActivity.kt" myButton.setOnClickListener { @@ -283,8 +283,8 @@ myButton.setOnClickListener { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="ExistingActivity.java" myButton.addOnClickListener(new OnClickListener() { @@ -299,8 +299,8 @@ myButton.addOnClickListener(new OnClickListener() { }); ``` -{% endtab %} -{% endtabs %} + + When using the `withCachedEngine()` factory method, pass the same ID that you used when caching the desired @@ -341,7 +341,7 @@ of Flutter, use a release build. #### Initial route with a cached engine -{% render docs/add-to-app/android-initial-route-cached-engine.md %} +{% render "docs/add-to-app/android-initial-route-cached-engine.md" %} ## Add a translucent Flutter screen @@ -390,8 +390,8 @@ with explicit transparency support. To launch your `FlutterActivity` with a transparent background, pass the appropriate `BackgroundMode` to the `IntentBuilder`: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="ExistingActivity.kt" // Using a new FlutterEngine. @@ -411,8 +411,8 @@ startActivity( ); ``` -{% endtab %} -{% tab "Java" %} + + ```java title="ExistingActivity.java" // Using a new FlutterEngine. @@ -432,8 +432,8 @@ startActivity( ); ``` -{% endtab %} -{% endtabs %} + + You now have a `FlutterActivity` with a transparent background. diff --git a/src/content/add-to-app/android/project-setup.md b/src/content/add-to-app/android/project-setup.md index c7fc74f8fec..7e16525ebe6 100644 --- a/src/content/add-to-app/android/project-setup.md +++ b/src/content/add-to-app/android/project-setup.md @@ -22,8 +22,8 @@ Plugin API to limit the supported architectures in your APK. Doing this avoids a missing `libflutter.so` runtime crash, for example: -{% tabs "android-build-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MyApp/app/build.gradle.kts" android { @@ -37,8 +37,8 @@ android { } ``` -{% endtab %} -{% tab "Groovy" %} + + ```groovy title="MyApp/app/build.gradle" android { @@ -52,8 +52,8 @@ android { } ``` -{% endtab %} -{% endtabs %} + + The Flutter engine also has an `x86_64` version. When using an emulator in debug Just-In-Time (JIT) mode, @@ -62,8 +62,8 @@ the Flutter module still runs correctly. ## Integrate your Flutter module -{% tabs %} -{% tab "With Android Studio" %} + + ### Integrate with Android Studio {:.no_toc} @@ -111,8 +111,8 @@ set your Project pane to display **Project Files**. This shows all files without filtering. ::: -{% endtab %} -{% tab "Without Android Studio" %} + + ### Integrate without Android Studio {:.no_toc} @@ -202,8 +202,8 @@ host Android app, make the following changes. 1. Add the `dependencyResolutionManagement` displayed in this step to the `settings.gradle` file. -{% tabs "settings.gradle.kts" %} -{% tab "Kotlin" %} + + ```kotlin title="settings.gradle.kts" dependencyResolutionManagement { @@ -217,8 +217,8 @@ dependencyResolutionManagement { } ``` -{% endtab %} -{% tab "Groovy" %} + + ```groovy title="settings.gradle" dependencyResolutionManagement { @@ -234,11 +234,11 @@ dependencyResolutionManagement { } ``` -{% endtab %} -{% endtabs %} + + -{% endtab %} -{% endtabs %} + + ## Add the Flutter module as a dependency @@ -257,8 +257,8 @@ existing app in Gradle. You can achieve this in two ways. one-click build process, but requires the Flutter SDK. This is the mechanism used by the Android Studio IDE plugin. -{% tabs %} -{% tab "Android Archive" %} + + ### Depend on the Android Archive (AAR) {:.no_toc} @@ -278,7 +278,7 @@ flutter build aar Then, follow the on-screen instructions to integrate. -{% render docs/app-figure.md, image:"development/add-to-app/android/project-setup/build-aar-instructions.png" %} + More specifically, this command creates (by default all debug/profile/release modes) @@ -312,8 +312,8 @@ to find these files. To do that, edit `settings.gradle` in your host app so that it includes the local repository and the dependency: -{% tabs "settings.gradle.kts" %} -{% tab "Kotlin" %} + + ```kotlin title="settings.gradle.kts" dependencyResolutionManagement { @@ -326,8 +326,8 @@ dependencyResolutionManagement { } ``` -{% endtab %} -{% tab "Groovy" %} + + ```groovy title="settings.gradle" dependencyResolutionManagement { @@ -346,13 +346,13 @@ dependencyResolutionManagement { maven { url = uri("https://storage.googleapis.com/download.flutter.io") } - // ...to before this line + // ...to before this line } } ``` -{% endtab %} -{% endtabs %} + +
@@ -361,7 +361,7 @@ dependencyResolutionManagement { After an `aar` build of a Kotlin DSL-based Android project, follow these steps to add the flutter_module. -Include the flutter module as a dependency in +Include the flutter module as a dependency in the Android project's `app/build.gradle` file. ```kotlin title="MyApp/app/build.gradle.kts" @@ -417,11 +417,11 @@ check out [Using Flutter in China][] page. You can also build an AAR for your Flutter module in Android Studio using the `Build > Flutter > Build AAR` menu. -{% render docs/app-figure.md, image:"development/add-to-app/android/project-setup/ide-build-aar.png" %} + ::: -{% endtab %} -{% tab "Module source code" %} +
+ ### Depend on the module's source code {:.no_toc} @@ -449,7 +449,7 @@ If you are using Kotlin, apply the following changes: ```kotlin title="MyApp/settings.gradle.kts" // Include the host app project. Assumed existing content. -include(":app") +include(":app") // Replace "flutter_module" with whatever package_name you supplied when you ran: // `$ flutter create -t module [package_name] val filePath = settingsDir.parentFile.toString() + "/flutter_module/.android/include_flutter.groovy" @@ -494,8 +494,8 @@ dependencies { This code is identical between Groovy and Kotlin. ::: -{% endtab %} -{% endtabs %} + +
Your app now includes the Flutter module as a dependency. diff --git a/src/content/add-to-app/debugging.md b/src/content/add-to-app/debugging.md index 7d2c906d2e2..8664aa8b6df 100644 --- a/src/content/add-to-app/debugging.md +++ b/src/content/add-to-app/debugging.md @@ -51,11 +51,11 @@ To hot restart (and rebuild state). press "R". ## Debug iOS extension in Xcode and VS Code -{% render docs/debug/debug-flow-ios.md, add:'launch' %} +{% render "docs/debug/debug-flow-ios.md", add:'launch' %} ## Debug Android extension in Android Studio -{% render docs/debug/debug-flow-androidstudio-as-start.md %} +{% render "docs/debug/debug-flow-androidstudio-as-start.md" %} [debugging functionalities]: /testing/debugging @@ -90,8 +90,7 @@ For an iOS target, complete the follow steps: 1. If your dev machine uses IPv6, add `--vm-service-host=::0`. - {% render docs/app-figure.md, img-class:"site-mobile-screenshot border", image:"development/add-to-app/debugging/wireless-port.png", - caption:"Arguments Passed On Launch with an IPv4 network added", width:"100%" %} + #### To determine if you're on an IPv6 network @@ -105,7 +104,7 @@ For an iOS target, complete the follow steps: 1. Check for an **IPv6 address** section. - {% render docs/app-figure.md, img-class:"site-mobile-screenshot border", image:"development/add-to-app/ipv6.png", caption:"WiFi dialog box for macOS System Settings", width:"60%" %} + ### Debug over Wi-Fi on Android devices diff --git a/src/content/add-to-app/index.md b/src/content/add-to-app/index.md index e27c881d321..0396bdb7266 100644 --- a/src/content/add-to-app/index.md +++ b/src/content/add-to-app/index.md @@ -48,7 +48,7 @@ various use-cases. Two of the most common use-cases are: ### Add to Android applications -{% render docs/app-figure.md, image:"development/add-to-app/android-overview.webp", alt:"Add-to-app steps on Android" %} + * Auto-build and import the Flutter module by adding a Flutter SDK hook to your Gradle script. @@ -70,7 +70,7 @@ various use-cases. Two of the most common use-cases are: ### Add to iOS applications -{% render docs/app-figure.md, image:"development/add-to-app/ios-overview.webp", alt:"Add-to-app steps on iOS" %} + * Auto-build and import the Flutter module by adding a Flutter SDK hook to your CocoaPods and to your Xcode build phase. diff --git a/src/content/add-to-app/ios/add-flutter-screen.md b/src/content/add-to-app/ios/add-flutter-screen.md index cfd16b35bb9..480e3ae166c 100644 --- a/src/content/add-to-app/ios/add-flutter-screen.md +++ b/src/content/add-to-app/ios/add-flutter-screen.md @@ -13,7 +13,7 @@ To launch a Flutter screen from an existing iOS app, you start a :::note The `FlutterEngine` serves as a host to the Dart VM and your Flutter runtime, -and the `FlutterViewController` attaches to a `FlutterEngine` to pass +and the `FlutterViewController` attaches to a `FlutterEngine` to pass input events into Flutter and to display frames rendered by the `FlutterEngine`. ::: @@ -39,13 +39,13 @@ trade-offs of pre-warming an engine. Where you create a `FlutterEngine` depends on your host app. -{% tabs "darwin-framework" %} -{% tab "SwiftUI" %} + + -In this example, we create a `FlutterEngine` object inside a SwiftUI [`Observable`][] -object called `FlutterDependencies`. -Pre-warm the engine by calling `run()`, and then inject this object -into a `ContentView` using the `environment()` view modifier. +In this example, we create a `FlutterEngine` object inside a SwiftUI [`Observable`][] +object called `FlutterDependencies`. +Pre-warm the engine by calling `run()`, and then inject this object +into a `ContentView` using the `environment()` view modifier. ```swift title="MyApp.swift" import SwiftUI @@ -77,8 +77,8 @@ struct MyApp: App { } ``` -{% endtab %} -{% tab "UIKit-Swift" %} + + As an example, we demonstrate creating a `FlutterEngine`, exposed as a property, on app startup in @@ -104,10 +104,10 @@ class AppDelegate: FlutterAppDelegate { // More on the FlutterAppDelegate. } ``` -{% endtab %} -{% tab "UIKit-ObjC" %} + + -The following example demonstrates creating a `FlutterEngine`, +The following example demonstrates creating a `FlutterEngine`, exposed as a property, on app startup in the app delegate. ```objc title="AppDelegate.h" @@ -140,20 +140,20 @@ exposed as a property, on app startup in the app delegate. @end ``` -{% endtab %} -{% endtabs %} + + ### Show a FlutterViewController with your FlutterEngine -{% tabs "darwin-framework" %} -{% tab "SwiftUI" %} + + -The following example shows a generic `ContentView` with a -[`NavigationLink`][] hooked to a flutter screen. -First, create a `FlutterViewControllerRepresentable` to represent the -`FlutterViewController`. The `FlutterViewController` constructor takes +The following example shows a generic `ContentView` with a +[`NavigationLink`][] hooked to a flutter screen. +First, create a `FlutterViewControllerRepresentable` to represent the +`FlutterViewController`. The `FlutterViewController` constructor takes the pre-warmed `FlutterEngine` as an argument, which is injected through -the view environment. +the view environment. ```swift title="ContentView.swift" import SwiftUI @@ -162,14 +162,14 @@ import Flutter struct FlutterViewControllerRepresentable: UIViewControllerRepresentable { // Flutter dependencies are passed in through the view environment. @Environment(FlutterDependencies.self) var flutterDependencies - + func makeUIViewController(context: Context) -> some UIViewController { return FlutterViewController( engine: flutterDependencies.flutterEngine, nibName: nil, bundle: nil) } - + func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} } @@ -187,12 +187,12 @@ struct ContentView: View { Now, you have a Flutter screen embedded in your iOS app. :::note -In this example, your Dart `main()` entrypoint function runs -when the `FlutterDependencies` observable is initialized. +In this example, your Dart `main()` entrypoint function runs +when the `FlutterDependencies` observable is initialized. ::: -{% endtab %} -{% tab "UIKit-Swift" %} + + The following example shows a generic `ViewController` with a `UIButton` hooked to present a [`FlutterViewController`][]. @@ -235,8 +235,8 @@ would run when calling `run` on the ::: -{% endtab %} -{% tab "UIKit-ObjC" %} + + The following example shows a generic `ViewController` with a `UIButton` hooked to present a [`FlutterViewController`][]. @@ -283,8 +283,8 @@ would run when calling `run` on the ::: -{% endtab %} -{% endtabs %} + + ### _Alternatively_ - Create a FlutterViewController with an implicit FlutterEngine @@ -304,8 +304,8 @@ To let the `FlutterViewController` present without an existing `FlutterEngine`, omit the `FlutterEngine` construction, and create the `FlutterViewController` without an engine reference. -{% tabs "darwin-framework" %} -{% tab "SwiftUI" %} + + ```swift title="ContentView.swift" import SwiftUI @@ -318,7 +318,7 @@ struct FlutterViewControllerRepresentable: UIViewControllerRepresentable { nibName: nil, bundle: nil) } - + func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} } @@ -333,8 +333,8 @@ struct ContentView: View { } ``` -{% endtab %} -{% tab "UIKit-Swift" %} + + ```swift title="ViewController.swift" // Existing code omitted. @@ -344,8 +344,8 @@ func showFlutter() { } ``` -{% endtab %} -{% tab "UIKit-ObjC" %} + + ```objc title="ViewController.m" // Existing code omitted. @@ -357,8 +357,8 @@ func showFlutter() { @end ``` -{% endtab %} -{% endtabs %} + + See [Loading sequence and performance][] for more explorations on latency and memory usage. @@ -372,13 +372,13 @@ The `FlutterAppDelegate` performs functions such as: * Forwarding application callbacks such as [`openURL`][] to plugins such as [local_auth][]. -* Keeping the Flutter connection open +* Keeping the Flutter connection open in debug mode when the phone screen locks. ### Creating a FlutterAppDelegate subclass -Creating a subclass of the `FlutterAppDelegate` in UIKit apps was shown -in the [Start a FlutterEngine and FlutterViewController section][]. -In a SwiftUI app, you can create a subclass of the +Creating a subclass of the `FlutterAppDelegate` in UIKit apps was shown +in the [Start a FlutterEngine and FlutterViewController section][]. +In a SwiftUI app, you can create a subclass of the `FlutterAppDelegate` and annotate it with the [`Observable()`][] macro as follows: ```swift title="MyApp.swift" @@ -424,14 +424,14 @@ import Flutter struct FlutterViewControllerRepresentable: UIViewControllerRepresentable { // Access the AppDelegate through the view environment. @Environment(AppDelegate.self) var appDelegate - + func makeUIViewController(context: Context) -> some UIViewController { return FlutterViewController( engine: appDelegate.flutterEngine, nibName: nil, bundle: nil) } - + func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} } @@ -455,8 +455,8 @@ Otherwise, plugins that depend on these events might have undefined behavior. For instance: -{% tabs "darwin-language" %} -{% tab "Swift" %} + + ```swift title="AppDelegate.swift" import Foundation @@ -516,8 +516,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, FlutterAppLifeCycleProvid } ``` -{% endtab %} -{% tab "Objective-C" %} + + ```objc title="AppDelegate.h" @import Flutter; @@ -632,8 +632,8 @@ performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))comp @end ``` -{% endtab %} -{% endtabs %} + + ## Launch options @@ -671,22 +671,22 @@ function in a specific file. For instance the following runs `myOtherEntrypoint()` in `lib/other_file.dart` instead of `main()` in `lib/main.dart`: -{% tabs "darwin-language" %} -{% tab "Swift" %} + + ```swift flutterEngine.run(withEntrypoint: "myOtherEntrypoint", libraryURI: "other_file.dart") ``` -{% endtab %} -{% tab "Objective-C" %} + + ```objc [flutterEngine runWithEntrypoint:@"myOtherEntrypoint" libraryURI:@"other_file.dart"]; ``` -{% endtab %} -{% endtabs %} + + ### Route @@ -695,8 +695,8 @@ Starting in Flutter version 1.22, an initial route can be set for your Flutter [`WidgetsApp`][] when constructing the FlutterEngine or the FlutterViewController. -{% tabs "darwin-language" %} -{% tab "Swift" %} + + ```swift let flutterEngine = FlutterEngine() @@ -705,8 +705,8 @@ engine.run( withEntrypoint: "main", initialRoute: "/onboarding") ``` -{% endtab %} -{% tab "Objective-C" %} + + ```objc FlutterEngine *flutterEngine = [[FlutterEngine alloc] init]; @@ -715,8 +715,8 @@ FlutterEngine *flutterEngine = [[FlutterEngine alloc] init]; initialRoute:@"/onboarding"]; ``` -{% endtab %} -{% endtabs %} + + This code sets your `dart:ui`'s [`PlatformDispatcher.defaultRouteName`][] to `"/onboarding"` instead of `"/"`. @@ -724,16 +724,16 @@ to `"/onboarding"` instead of `"/"`. Alternatively, to construct a FlutterViewController directly without pre-warming a FlutterEngine: -{% tabs "darwin-language" %} -{% tab "Swift" %} + + ```swift let flutterViewController = FlutterViewController( project: nil, initialRoute: "/onboarding", nibName: nil, bundle: nil) ``` -{% endtab %} -{% tab "Objective-C" %} + + ```objc FlutterViewController* flutterViewController = @@ -743,8 +743,8 @@ FlutterViewController* flutterViewController = bundle:nil]; ``` -{% endtab %} -{% endtabs %} + + :::tip In order to imperatively change your current Flutter diff --git a/src/content/add-to-app/ios/project-setup.md b/src/content/add-to-app/ios/project-setup.md index ac5620480e8..a8cedc42b9d 100644 --- a/src/content/add-to-app/ios/project-setup.md +++ b/src/content/add-to-app/ios/project-setup.md @@ -115,23 +115,23 @@ To use Flutter debugging features such as hot reload, consult [Debugging your add-to-app module][]. ::: -{% tabs %} -{% tab "Use CocoaPods" %} + + -{% render docs/add-to-app/ios-project/embed-cocoapods.md %} +{% render "docs/add-to-app/ios-project/embed-cocoapods.md" %} -{% endtab %} -{% tab "Use frameworks" %} + + -{% render docs/add-to-app/ios-project/embed-frameworks.md %} +{% render "docs/add-to-app/ios-project/embed-frameworks.md" %} -{% endtab %} -{% tab "Use frameworks and CocoaPods" %} + + -{% render docs/add-to-app/ios-project/embed-split.md %} +{% render "docs/add-to-app/ios-project/embed-split.md" %} -{% endtab %} -{% endtabs %} + + ## Set local network privacy permissions @@ -183,7 +183,7 @@ Adjust the names as needed depending on your app's build configurations. 1. In the **Project Navigator**, click on `Info-Debug.plist`. - 1. Select **File** > **Duplicate...**. + 1. Select **File** > **Duplicate...**. You can also press Cmd + Shift + S. 1. In the dialog box, set the **Save As:** field to @@ -199,7 +199,7 @@ Adjust the names as needed depending on your app's build configurations. 1. _(Optional)_ To set your desired customized permission dialog text, add the key **Privacy - Local Network Usage Description**. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/debug-plist.png", caption:"The `Info-Debug` property list with the **Bonjour Services** and **Privacy - Local Network Usage Description** keys added" %} + 1. Set the target to use different property lists for different build modes. @@ -209,7 +209,7 @@ Adjust the names as needed depending on your app's build configurations. 1. Click **All** and **Combined** sub-tabs. - 1. In the Search box, type `plist`. + 1. In the Search box, type `plist`. This limits the settings to those that include property lists. 1. Scroll through the list until you see **Packaging**. @@ -219,12 +219,12 @@ Adjust the names as needed depending on your app's build configurations. 1. Change the **Info.plist File** value from `path/to/Info.plist` to `path/to/Info-$(CONFIGURATION).plist`. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/set-plist-build-setting.png", caption:"Updating the `Info.plist` build setting to use build mode-specific property lists" %} + This resolves to the path **Info-Debug.plist** in **Debug** and **Info-Release.plist** in **Release**. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/plist-build-setting.png", caption:"The updated **Info.plist File** build setting displaying the configuration variations" %} + 1. Remove the **Release** property list from the **Build Phases**. @@ -238,7 +238,7 @@ Adjust the names as needed depending on your app's build configurations. click on it and then click the **-** (minus sign) under it to remove the property list from the resources list. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/copy-bundle.png", caption:"The **Copy Bundle** build phase displaying the **Info-Release.plist** setting. Remove this setting." %} + 1. The first Flutter screen your Debug app loads prompts for local network permission. @@ -280,7 +280,7 @@ exclude `arm64` from the simulator architectures in your host app. 1. Type `arm64` in the **Debug > Any iOS Simulator SDK** dialog box. - {% render docs/captioned-image.liquid, image:"development/add-to-app/ios/project-setup/excluded-archs.png", caption:"Add `arm64` as an excluded architecture for your app" %} + 1. Press Esc to close this dialog box. diff --git a/src/content/add-to-app/multiple-flutters.md b/src/content/add-to-app/multiple-flutters.md index 13d12f7d0a2..0bcaadcc0e3 100644 --- a/src/content/add-to-app/multiple-flutters.md +++ b/src/content/add-to-app/multiple-flutters.md @@ -2,7 +2,7 @@ title: Multiple Flutter screens or views shortTitle: Add multiple Flutters description: > - How to integrate multiple instances of + How to integrate multiple instances of Flutter engine, screens, or views to your application. --- @@ -80,7 +80,7 @@ or other planned work on enhancing multiple Flutter instances, check out You can find a sample demonstrating how to use `FlutterEngineGroup` on both Android and iOS on [GitHub][]. -{% render docs/app-figure.md, image:"development/add-to-app/multiple-flutters-sample.webp", alt:"A sample demonstrating multiple-Flutters" %} + [GitHub]: {{site.repo.samples}}/tree/main/add_to_app/multiple_flutters [`FlutterActivity`]: {{site.api}}/javadoc/io/flutter/embedding/android/FlutterActivity.html diff --git a/src/content/app-architecture/case-study/index.md b/src/content/app-architecture/case-study/index.md index f7bb9daaa15..f6ce2fd84d1 100644 --- a/src/content/app-architecture/case-study/index.md +++ b/src/content/app-architecture/case-study/index.md @@ -21,10 +21,10 @@ In these ways and more, it simulates a real-world, feature-rich Flutter application.
- {% render docs/app-figure.md, image:"app-architecture/case-study/splash_screen.png", alt:"A screenshot of the splash screen of the compass app.", img-style:"max-height: 400px;" %} - {% render docs/app-figure.md, image:"app-architecture/case-study/home_screen.png", alt:"A screenshot of the home screen of the compass app.", img-style:"max-height: 400px;" %} - {% render docs/app-figure.md, image:"app-architecture/case-study/search_form_screen.png", alt:"A screenshot of the search form screen of the compass app.", img-style:"max-height: 400px;" %} - {% render docs/app-figure.md, image:"app-architecture/case-study/booking_screen.png", alt:"A screenshot of the booking screen of the compass app.", img-style:"max-height: 400px;" %} + + + +
The Compass app's architecture most resembles the [MVVM architectural pattern][] diff --git a/src/content/app-architecture/case-study/ui-layer.md b/src/content/app-architecture/case-study/ui-layer.md index dfa55463106..21e9c003d0d 100644 --- a/src/content/app-architecture/case-study/ui-layer.md +++ b/src/content/app-architecture/case-study/ui-layer.md @@ -90,7 +90,7 @@ class HomeViewModel { required UserRepository userRepository, }) : _bookingRepository = bookingRepository, _userRepository = userRepository; - + final BookingRepository _bookingRepository; final UserRepository _userRepository; @@ -98,7 +98,7 @@ class HomeViewModel { User? get user => _user; List _bookings = []; - + /// Items in an [UnmodifiableListView] can't be directly modified, /// but changes in the source list can be modified. Since _bookings /// is private and bookings is not, the view has no way to modify the @@ -404,7 +404,7 @@ a [`Dismissible`][] widget. Recall this code from the previous snippet: -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"app-architecture/case-study/dismissible.webp", img-style:"max-height: 480px; border-radius: 12px; border: black 2px solid;", alt: "A clip that demonstrates the 'dismissible' functionality of the Compass app." diff --git a/src/content/app-architecture/design-patterns.md b/src/content/app-architecture/design-patterns.md index 0b4ce8a057b..b200cc5a345 100644 --- a/src/content/app-architecture/design-patterns.md +++ b/src/content/app-architecture/design-patterns.md @@ -15,12 +15,11 @@ or if you're comfortable with Flutter and the MVVM pattern, the following articles are for you. These articles aren't about high-level app architecture, -rather they're about solving specific design problems that improve your +rather they're about solving specific design problems that improve your application's code base regardless of how you've architected your app. -That said, the articles do assume the MVVM pattern laid out on the +That said, the articles do assume the MVVM pattern laid out on the previous pages in the code examples. -{% assign recipes = collections.design-patterns | sort: "data.order" -%} -{% render expansion-list.html, list: recipes, baseId: 'design-patterns' %} + [architecture guide]: /app-architecture/guide diff --git a/src/content/app-architecture/design-patterns/command.md b/src/content/app-architecture/design-patterns/command.md index 67216c1ffd9..ab0546bd12d 100644 --- a/src/content/app-architecture/design-patterns/command.md +++ b/src/content/app-architecture/design-patterns/command.md @@ -7,9 +7,6 @@ contentTags: - state iconPath: /assets/images/docs/app-architecture/design-patterns/command-icon.svg order: 4 -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/app-architecture/design-patterns/design-patterns.json b/src/content/app-architecture/design-patterns/design-patterns.json deleted file mode 100644 index 3f2929c1265..00000000000 --- a/src/content/app-architecture/design-patterns/design-patterns.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "tags": "design-patterns" -} diff --git a/src/content/app-architecture/design-patterns/key-value-data.md b/src/content/app-architecture/design-patterns/key-value-data.md index 6c62378dde1..c800bd8946c 100644 --- a/src/content/app-architecture/design-patterns/key-value-data.md +++ b/src/content/app-architecture/design-patterns/key-value-data.md @@ -7,9 +7,6 @@ contentTags: - dark mode iconPath: /assets/images/docs/app-architecture/design-patterns/kv-store-icon.svg order: 1 -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/app-architecture/design-patterns/offline-first.md b/src/content/app-architecture/design-patterns/offline-first.md index 1e6e764035d..ec09111a78e 100644 --- a/src/content/app-architecture/design-patterns/offline-first.md +++ b/src/content/app-architecture/design-patterns/offline-first.md @@ -7,9 +7,6 @@ contentTags: - repository pattern iconPath: /assets/images/docs/app-architecture/design-patterns/offline-first-icon.svg order: 3 -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/app-architecture/design-patterns/optimistic-state.md b/src/content/app-architecture/design-patterns/optimistic-state.md index 5e9d20d5873..852846c3302 100644 --- a/src/content/app-architecture/design-patterns/optimistic-state.md +++ b/src/content/app-architecture/design-patterns/optimistic-state.md @@ -6,9 +6,6 @@ contentTags: - asynchronous dart iconPath: /assets/images/docs/app-architecture/design-patterns/optimistic-state-icon.svg order: 0 -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/app-architecture/design-patterns/result.md b/src/content/app-architecture/design-patterns/result.md index 3960dc7447b..955edd95657 100644 --- a/src/content/app-architecture/design-patterns/result.md +++ b/src/content/app-architecture/design-patterns/result.md @@ -6,9 +6,6 @@ contentTags: - services iconPath: /assets/images/docs/app-architecture/design-patterns/result-icon.svg order: 5 -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -463,7 +460,7 @@ final class Error extends Result { } ``` -[Error handling documentation]: {{site.dart-site}}/language/error-handling +[Error handling documentation]: https://dart.dev/language/error-handling [Flutter architecture guidelines]: /app-architecture [Compass App example]: {{site.repo.samples}}/tree/main/compass_app [pub.dev]: {{site.pub}} diff --git a/src/content/app-architecture/design-patterns/sql.md b/src/content/app-architecture/design-patterns/sql.md index 86b97b0e2b5..daac2603361 100644 --- a/src/content/app-architecture/design-patterns/sql.md +++ b/src/content/app-architecture/design-patterns/sql.md @@ -6,9 +6,6 @@ contentTags: - SQL iconPath: /assets/images/docs/app-architecture/design-patterns/sql-icon.svg order: 2 -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/app-architecture/recommendations.md b/src/content/app-architecture/recommendations.md index 012cd4f8c4f..83322813698 100644 --- a/src/content/app-architecture/recommendations.md +++ b/src/content/app-architecture/recommendations.md @@ -26,38 +26,54 @@ which reflects how strongly the Flutter team recommends it. fundamentally clash with your current approach. * **Recommend**: This practice will likely improve your app. * **Conditional**: This practice can improve your app in certain circumstances. -

{% for section in architectureRecommendations %} -

{{section.category}}

-

{{section.description}}

- - - - - - {% for rec in section.recommendations %} - - - - {% endfor %} +## {{section.category}} + +{{section.description}} + +{% if section.recommendations.size > 0 %} + +
RecommendationDescription
-

{{rec.recommendation}}

- {% if rec.confidence == "strong" %} -
Strongly recommend
- {% elsif rec.confidence == "recommend" %} -
Recommend
- {% else %} -
Conditional
- {% endif %} -
- {{rec.description}} -
- {{rec.confidence-description}}
+ + + + + + + +{% for rec in section.recommendations %} + + + + +{% endfor %} +
RecommendationDescription
+ + {{rec.recommendation}} + +{% if rec.confidence == "strong" %} +
Strongly recommend
+{% elsif rec.confidence == "recommend" %} +
Recommend
+{% else %} +
Conditional
+{% endif %} + +
+ + {{rec.description}} + {{rec.confidence-description}} + +
-
+ +{% endif %} {% endfor %} -## Recommended resources + + +## Recommended resources {:#resources} * Code and templates * [Compass app source code][] - diff --git a/src/content/assets/css/main.scss b/src/content/assets/css/main.scss deleted file mode 100644 index ddaffcf821e..00000000000 --- a/src/content/assets/css/main.scss +++ /dev/null @@ -1,5 +0,0 @@ ---- -layout: none ---- - -@forward '../../../_sass/site'; diff --git a/src/content/assets/js/archive.js b/src/content/assets/js/archive.js deleted file mode 100644 index 87240f8833e..00000000000 --- a/src/content/assets/js/archive.js +++ /dev/null @@ -1,325 +0,0 @@ -// Number of releases to show by default (rest will be behind a "show all" link). -const releasesToShow = 99999; - -// The Flutter SDK archive filename prefix. -const FILE_NAME_PREFIX = 'flutter_'; - -const filenameReplacement = new RegExp(`^(.*)(\\bflutter_\\w+_v?([X|0-9]\\.)+[zipxztar\\.]{2,3})`, 'm'); -// const filenameReplacement = new RegExp(`^((.*) )* (.*?)\\b${FILE_NAME_PREFIX}\\w+_v?[X|0-9]+\\..* (.*)`, 'm'); -// const filenameReplacement = new RegExp(`^(.*?)\\b{FILE_NAME_PREFIX}\\w+_v?([X|0-9]+\\.)+[zip|tar\\.xz](.*)$`, 'm'); -// const filenameReplacement = new RegExp(`\\b{FILE_NAME_PREFIX}\\w+_v?\\d+(\\.\\d+)+\\.(zip|tar\\.xz)\\b`, 'm'); - -// Fetches Flutter release JSON for the given OS and calls the callback once the data is available. -function fetchFlutterReleases(os, callback, errorCallback) { - // OS: windows, macos, linux - const url = `https://storage.googleapis.com/flutter_infra_release/releases/releases_${os}.json`; - fetch(url, { method: 'GET' }) - .then(response => response.json()) - .then(data => callback(data, os)) - .catch(_ => { - if (errorCallback) { - errorCallback(os); - } - }); -} - -function updateTable(releases, os) { - const releaseData = releases.releases; - - for (const channel in releases.current_release) { - const table = document.getElementById(`downloads-${os}-${channel}`); - - // Table is not present when the channel is `dev`. - if (!table) { - continue; - } - - const tableBody = table.querySelector('tbody'); - - table.classList.add('collapsed'); - const loadingElements = table.querySelectorAll('.loading'); - loadingElements.forEach(function (element) { - element.remove(); - }); - - const releasesForChannel = releaseData.filter(function (release) { - return release.channel === channel; - }); - - releasesForChannel.forEach(function (release, index) { - // If this is the first row after the cut-off, insert the "Show more..." link. - if (index === releasesToShow) { - const showAll = document.createElement('a'); - showAll.textContent = 'Show all...'; - showAll.href = '#'; - showAll.addEventListener('click', function (event) { - this.closest('table').classList.remove('collapsed'); - this.closest('tr').remove(); - event.preventDefault(); - }); - - const row = document.createElement('tr'); - const cell = document.createElement('td'); - cell.colSpan = 6; - cell.appendChild(showAll); - row.appendChild(cell); - tableBody.appendChild(row); - } - - const row = document.createElement('tr'); - if (index >= releasesToShow) { - row.classList.add('overflow'); - } - tableBody.appendChild(row); - - const hashLabel = document.createElement('span'); - hashLabel.textContent = release.hash.substr(0, 7); - hashLabel.classList.add('git-hash'); - - const url = releases.base_url + '/' + release.archive; - const downloadLink = document.createElement('a'); - downloadLink.href = url; - downloadLink.textContent = release.version; - - const dartSdkVersion = document.createElement('span'); - dartSdkVersion.textContent = release.dart_sdk_version ? release.dart_sdk_version.split(' ')[0] : '-'; - - const dartSdkArch = document.createElement('span'); - dartSdkArch.textContent = release.dart_sdk_arch ? release.dart_sdk_arch : 'x64'; - - const date = new Date(Date.parse(release.release_date)); - - const provenance = getProvenanceLink(os, release, date, channel); - - - const cells = [ - createTableCell(downloadLink), - createTableCell(dartSdkArch), - createTableCell(hashLabel), - createTableCell(date.toLocaleDateString(), 'date'), - createTableCell(dartSdkVersion), - createTableCell(provenance) - ]; - - cells.forEach(function (cell) { - row.appendChild(cell); - }); - }); - } -} - -/** - * Create a new individual cell for HTML table. - * - * @param {string | Node} content - The content to be set in the cell. - * @param {string | null | undefined} dataClass - The class to be set in the cell. - * @returns {HTMLElement} The created table cell element. - */ -function createTableCell(content, dataClass) { - const cell = document.createElement('td'); - - if (dataClass) { - cell.classList.add(dataClass); - } - - if (typeof content === 'string') { - cell.textContent = content; - } else { - cell.appendChild(content); - } - - return cell; -} - -function updateTableFailed(os) { - const tab = document.getElementById(`tab-os-${os}`); - if (!tab) return; - const loadingElements = tab.querySelectorAll('.loading'); - loadingElements.forEach(function (element) { - element.textContent = 'Failed to load releases. Refresh page to try again.'; - }); -} - -let macOSArm64ArchiveFilename = ''; - -// Listen for the macOS arm64 download link to be clicked and update -// the example unzip command with correct arm64 filename -(() => { - const macDownload = document.querySelector('.download-latest-link-macos-arm64'); - if (!macDownload) { - return; - } - macDownload.addEventListener('click', function () { - // Update inlined filenames in element text nodes with arm64 filename: - replaceFilenameInCodeElements(macOSArm64ArchiveFilename); - }); -})(); - -/** - * Replaces the placeholder text or the old filename in code blocks - * with the specified {@link archiveFilename}. - * - * @param archiveFilename The new filename to replace the - * old one in code blocks with - */ -function replaceFilenameInCodeElements(archiveFilename) { - const codeElements = document.querySelectorAll('code'); - - codeElements.forEach((codeElement) => { - // Check if the element itself needs replacement - const codeElementText = codeElement.innerHTML; - if (codeElementText.includes(FILE_NAME_PREFIX) && - filenameReplacement.test(codeElementText)) { - codeElement.innerHTML = codeElementText.replace( - filenameReplacement, - `$1${archiveFilename}` - ); - } - - // Process child nodes as before - codeElement.childNodes.forEach((node) => { - const nodeText = node.textContent; - if (node.nodeType === Node.TEXT_NODE && - nodeText.includes(FILE_NAME_PREFIX)) { - node.textContent = nodeText.replace( - filenameReplacement, - `$1${archiveFilename}` - ); - } - }); - }); -} - - -/** - * Update the download button for the latest release. - * @param {Array} releases - A list of Flutter releases - * @param {string} base_url - link for sdk download link such as storage.googleapis.com... - * @param {string} os - macos, windows, or linux - * @param {string} [arch=''] - Only specify if there's additional architecture, such as arm64 - */ -function updateReleaseDownloadButton(releases, base_url, os, arch = '') { - const archString = !arch.length ? '' : `-${arch}`; - - const release = releases[0]; - const linkSegments = release.archive.split('/'); - const archiveFilename = linkSegments[linkSegments.length - 1]; // Just the filename part of url - - if (os === 'macos' && arch === 'arm64') { - macOSArm64ArchiveFilename = archiveFilename; - } - - const downloadLink = document.querySelectorAll(`.download-latest-link-${os}${archString}`); - downloadLink.forEach((link) => { - link.textContent = archiveFilename; - link.setAttribute('href', `${base_url}/${release.archive}`); - }) - - //Update download-filename placeholders: - const downloadLinkOs = document.querySelectorAll(`.download-latest-link-filename-${os}${archString}`); - downloadLinkOs.forEach(function (element) { - element.textContent = archiveFilename; - }); - - const genericDownloadLink = document.querySelectorAll('.download-latest-link-filename'); - genericDownloadLink.forEach(function (element) { - element.textContent = archiveFilename; - }); - - // Update inlined filenames in element text nodes: - replaceFilenameInCodeElements(archiveFilename); -} - -function updateDownloadLink(releases, os, arch) { - const channel = 'stable'; - const releasesOrDefault = releases?.releases ?? []; - const releasesForChannel = Array.from(releasesOrDefault).filter(function (release) { - return release.channel === channel; - }); - if (!releasesForChannel.length) - return; - - // On macOS, update the download buttons for both architectures, x64 and arm64 - if (os === 'macos') { - // Filter releases by x64 architecture - const releasesForX64 = releasesForChannel.filter(function (release) { - return release.dart_sdk_arch === 'x64'; - }); - - // Filter releases by arm64 architecture - const releasesForArm64 = releasesForChannel.filter(function (release) { - return release.dart_sdk_arch === 'arm64'; - }); - - // If no arm64 releases available, delete all apple silicon elements - if (!releasesForArm64.length) { - const appleSiliconElements = document.querySelectorAll('.apple-silicon'); - appleSiliconElements.forEach(function (element) { - element.remove(); - }); - - return; - } - - updateReleaseDownloadButton(releasesForArm64, releases.base_url, os, 'arm64'); - updateReleaseDownloadButton(releasesForX64, releases.base_url, os); - } else { - updateReleaseDownloadButton(releasesForChannel, releases.base_url, os); - } -} - -function updateDownloadLinkFailed(os) { - const allDownloadLinks = document.querySelectorAll(`.download-latest-link-${os}`); - allDownloadLinks.forEach(function (link) { - link.textContent = '(failed)'; - }); -} - -function getProvenanceLink(os, release, date, channel) { - const baseUrl = 'https://storage.googleapis.com/flutter_infra_release/releases/'; - if (os === 'windows' && date < new Date(Date.parse('4/3/2023'))) { - // provenance not available before 4/3/2023 for Windows - const spanElement = document.createElement('span'); - spanElement.textContent = '-'; - return spanElement; - } else if (date < new Date(Date.parse('12/15/2022'))) { - // provenance not available before 12/15/2022 for macOS and Linux - const spanElement = document.createElement('span'); - spanElement.textContent = '-'; - return spanElement; - } - - const extension = os === 'linux' ? 'tar.xz' : 'zip'; - const provenanceAnchor = document.createElement('a'); - provenanceAnchor.href = `${baseUrl}${channel}/${os}/flutter_${os}_${release.version}-${channel}.${extension}.intoto.jsonl`; - provenanceAnchor.textContent = `Attestation bundle`; - provenanceAnchor.target = '_blank'; - return provenanceAnchor; -} - - -// Send requests to render the tables. -document.addEventListener("DOMContentLoaded", function(_) { - const foundSdkArchivesElement = document.querySelector('.tabs-wrapper[data-tab-save-key="os-archive-tabs"]') !== null; - if (foundSdkArchivesElement) { - fetchFlutterReleases('windows', updateTable, updateTableFailed); - fetchFlutterReleases('macos', updateTable, updateTableFailed); - fetchFlutterReleases('linux', updateTable, updateTableFailed); - } - - // The checks below come from getting started page. see https://github.com/flutter/website/issues/8889#issuecomment-1639033078 - const foundLatestWindows = document.getElementsByClassName('download-latest-link-windows').length > 0; - if (foundLatestWindows) { - fetchFlutterReleases('windows', updateDownloadLink, updateDownloadLinkFailed); - } - - const foundLatestMacOS = document.getElementsByClassName('download-latest-link-macos').length > 0; - if (foundLatestMacOS) { - fetchFlutterReleases('macos', updateDownloadLink, updateDownloadLinkFailed); - } - - const foundLatestLinux = document.getElementsByClassName('download-latest-link-linux').length > 0; - if (foundLatestLinux) { - fetchFlutterReleases('linux', updateDownloadLink, updateDownloadLinkFailed); - } -}); diff --git a/src/content/assets/js/inject_dartpad.dart.js b/src/content/assets/js/inject_dartpad.dart.js deleted file mode 100644 index 4a41e2a0896..00000000000 --- a/src/content/assets/js/inject_dartpad.dart.js +++ /dev/null @@ -1,2723 +0,0 @@ -(function dartProgram(){function copyProperties(a,b){var s=Object.keys(a) -for(var r=0;r=0)return true -if(typeof version=="function"&&version.length==0){var q=version() -if(/^\d+\.\d+\.\d+\.\d+$/.test(q))return true}}catch(p){}return false}() -function inherit(a,b){a.prototype.constructor=a -a.prototype["$i"+a.name]=a -if(b!=null){if(z){Object.setPrototypeOf(a.prototype,b.prototype) -return}var s=Object.create(b.prototype) -copyProperties(a.prototype,s) -a.prototype=s}}function inheritMany(a,b){for(var s=0;s0;b=s){s=b-1 -r=a.charCodeAt(s) -if(r!==32&&r!==13&&!J.Ga(r))break}return b}, -U6(a){if(typeof a=="string")return J.Dr.prototype -if(a==null)return a -if(Array.isArray(a))return J.p.prototype -if(typeof a!="object"){if(typeof a=="function")return J.c5.prototype -if(typeof a=="symbol")return J.Dw.prototype -if(typeof a=="bigint")return J.rQ.prototype -return a}if(a instanceof A.a)return a -return J.M3(a)}, -c(a){if(typeof a=="number"){if(Math.floor(a)==a)return J.im.prototype -return J.kD.prototype}if(typeof a=="string")return J.Dr.prototype -if(a==null)return J.CD.prototype -if(typeof a=="boolean")return J.yE.prototype -if(Array.isArray(a))return J.p.prototype -if(typeof a!="object"){if(typeof a=="function")return J.c5.prototype -if(typeof a=="symbol")return J.Dw.prototype -if(typeof a=="bigint")return J.rQ.prototype -return a}if(a instanceof A.a)return a -return J.M3(a)}, -w1(a){if(a==null)return a -if(Array.isArray(a))return J.p.prototype -if(typeof a!="object"){if(typeof a=="function")return J.c5.prototype -if(typeof a=="symbol")return J.Dw.prototype -if(typeof a=="bigint")return J.rQ.prototype -return a}if(a instanceof A.a)return a -return J.M3(a)}, -CR(a){return J.c(a).gbx(a)}, -GA(a,b){return J.w1(a).F(a,b)}, -Hm(a){return J.U6(a).gB(a)}, -IT(a){return J.w1(a).gkz(a)}, -M1(a,b,c){return J.w1(a).E2(a,b,c)}, -Nu(a){return J.c(a).gi(a)}, -cf(a,b){if(a==null)return b==null -if(typeof a!="object")return b!=null&&a===b -return J.c(a).DN(a,b)}, -n(a){return J.c(a)["["](a)}, -vB:function vB(){}, -yE:function yE(){}, -CD:function CD(){}, -MF:function MF(){}, -u0:function u0(){}, -iC:function iC(){}, -kd:function kd(){}, -c5:function c5(){}, -rQ:function rQ(){}, -Dw:function Dw(){}, -p:function p(a){this.$ti=a}, -B:function B(){}, -Po:function Po(a){this.$ti=a}, -D:function D(a,b,c){var _=this -_.a=a -_.b=b -_.c=0 -_.d=null -_.$ti=c}, -qI:function qI(){}, -im:function im(){}, -kD:function kD(){}, -Dr:function Dr(){}},A={FK:function FK(){}, -G(a){return new A.SH("Field '"+a+"' has been assigned during initialization.")}, -la(a){return new A.SH("Field '"+a+"' has not been initialized.")}, -oo(a){var s,r=a^48 -if(r<=9)return r -s=a|32 -if(97<=s&&s<=102)return s-87 -return-1}, -yc(a,b){a=a+b&536870911 -a=a+((a&524287)<<10)&536870911 -return a^a>>>6}, -qL(a){a=a+((a&67108863)<<3)&536870911 -a^=a>>>11 -return a+((a&16383)<<15)&536870911}, -ks(a){var s,r -for(s=$.Qu.length,r=0;r").Kq(d).C("xy<1,2>")) -return new A.i1(a,b,c.C("@<0>").Kq(d).C("i1<1,2>"))}, -Wp(){return new A.lj("No element")}, -SH:function SH(a){this.a=a}, -zl:function zl(){}, -bQ:function bQ(){}, -aL:function aL(){}, -a7:function a7(a,b,c){var _=this -_.a=a -_.b=b -_.c=0 -_.d=null -_.$ti=c}, -i1:function i1(a,b,c){this.a=a -this.b=b -this.$ti=c}, -xy:function xy(a,b,c){this.a=a -this.b=b -this.$ti=c}, -MH:function MH(a,b,c){var _=this -_.a=null -_.b=a -_.c=b -_.$ti=c}, -A8:function A8(a,b,c){this.a=a -this.b=b -this.$ti=c}, -SU:function SU(){}, -H(a){var s=v.mangledGlobalNames[a] -if(s!=null)return s -return"minified:"+a}, -wV(a,b){var s -if(b!=null){s=b.x -if(s!=null)return s}return t.p.b(a)}, -I(a){var s -if(typeof a=="string")return a -if(typeof a=="number"){if(a!==0)return""+a}else if(!0===a)return"true" -else if(!1===a)return"false" -else if(a==null)return"null" -s=J.n(a) -return s}, -eQ(a){var s,r=$.xu -if(r==null)r=$.xu=Symbol("identityHashCode") -s=a[r] -if(s==null){s=Math.random()*0x3fffffff|0 -a[r]=s}return s}, -Hp(a,b){var s,r,q,p,o,n=null,m=/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i.exec(a) -if(m==null)return n -s=m[3] -if(b==null){if(s!=null)return parseInt(a,10) -if(m[2]!=null)return parseInt(a,16) -return n}if(b<2||b>36)throw A.L(A.TE(b,2,36,"radix",n)) -if(b===10&&s!=null)return parseInt(a,10) -if(b<10||s==null){r=b<=10?47+b:86+b -q=m[1] -for(p=q.length,o=0;or)return n}return parseInt(a,b)}, -l(a){var s,r,q,p -if(a instanceof A.a)return A.d(A.z(a),null) -s=J.c(a) -if(s===B.Ok||s===B.Ub||t.o.b(a)){r=B.O4(a) -if(r!=="Object"&&r!=="")return r -q=a.constructor -if(typeof q=="function"){p=q.name -if(typeof p=="string"&&p!=="Object"&&p!=="")return p}}return A.d(A.z(a),null)}, -i(a){var s,r,q -if(a==null||typeof a=="number"||A.y(a))return J.n(a) -if(typeof a=="string")return JSON.stringify(a) -if(a instanceof A.t)return a["["](0) -if(a instanceof A.M)return a.k(!0) -s=$.u() -for(r=0;r<1;++r){q=s[r].R(a) -if(q!=null)return q}return"Instance of '"+A.l(a)+"'"}, -fw(a,b,c){var s,r,q,p -if(c<=500&&b===0&&c===a.length)return String.fromCharCode.apply(null,a) -for(s=b,r="";s>>0,s&1023|56320)}}throw A.L(A.TE(a,0,1114111,null,null))}, -au(a,b,c){if(a>c)return A.TE(a,0,c,"start",null) -if(b!=null)if(bc)return A.TE(b,a,c,"end",null) -return new A.AT(!0,b,"end",null)}, -tL(a){return new A.AT(!0,a,null,null)}, -L(a){return A.r(a,new Error())}, -r(a,b){var s -if(a==null)a=new A.E() -b.dartException=a -s=A.J -if("defineProperty" in Object){Object.defineProperty(b,"message",{get:s}) -b.name=""}else b.toString=s -return b}, -J(){return J.n(this.dartException)}, -v(a,b){throw A.r(a,b==null?new Error():b)}, -cW(a,b,c){var s -if(b==null)b=0 -if(c==null)c=0 -s=Error() -A.v(A.HK(a,b,c),s)}, -HK(a,b,c){var s,r,q,p,o,n,m,l,k -if(typeof b=="string")s=b -else{r="[]=;add;removeWhere;retainWhere;removeRange;setRange;setInt8;setInt16;setInt32;setUint8;setUint16;setUint32;setFloat32;setFloat64".split(";") -q=r.length -p=b -if(p>q){c=p/q|0 -p%=q}s=r[p]}o=typeof c=="string"?c:"modify;remove from;add to".split(";")[c] -n=t.j.b(a)?"list":"ByteData" -m=a.$flags|0 -l="a " -if((m&4)!==0)k="constant " -else if((m&2)!==0){k="unmodifiable " -l="an "}else k=(m&1)!==0?"fixed-length ":"" -return new A.ub("'"+s+"': Cannot "+o+" "+l+k+n)}, -lk(a){throw A.L(A.a4(a))}, -CU(a){if(a==null)return J.Nu(a) -if(typeof a=="object")return A.eQ(a) -return J.Nu(a)}, -dJ(a,b){var s,r,q,p=a.length -for(s=0;s=0}, -S0:function S0(a,b){this.a=a -this.b=b}, -rY:function rY(){}, -t:function t(){}, -E1:function E1(){}, -lc:function lc(){}, -zx:function zx(){}, -rT:function rT(a,b){this.a=a -this.b=b}, -Eq:function Eq(a){this.a=a}, -N5:function N5(a){var _=this -_.a=0 -_.f=_.e=_.d=_.c=_.b=null -_.r=0 -_.$ti=a}, -vh:function vh(a,b){var _=this -_.a=a -_.b=b -_.d=_.c=null}, -Gp:function Gp(a,b){this.a=a -this.$ti=b}, -N6:function N6(a,b,c){var _=this -_.a=a -_.b=b -_.c=c -_.d=null}, -dC:function dC(a){this.a=a}, -wN:function wN(a){this.a=a}, -VX:function VX(a){this.a=a}, -M:function M(){}, -B7:function B7(){}, -VR:function VR(a,b){var _=this -_.a=a -_.b=b -_.e=_.d=_.c=null}, -rM(a,b,c){var s -if(!(a>>>0!==a))s=b>>>0!==b||a>b||b>c -else s=!0 -if(s)throw A.L(A.au(a,b,c)) -return b}, -WZ:function WZ(){}, -eH:function eH(){}, -df:function df(){}, -b0:function b0(){}, -Dg:function Dg(){}, -DV:function DV(){}, -zU:function zU(){}, -K8:function K8(){}, -xj:function xj(){}, -dE:function dE(){}, -Zc:function Zc(){}, -wf:function wf(){}, -Pq:function Pq(){}, -eE:function eE(){}, -V6:function V6(){}, -RG:function RG(){}, -vX:function vX(){}, -WB:function WB(){}, -VS:function VS(){}, -xZ(a,b){var s=b.c -return s==null?b.c=A.Q2(a,"b8",[b.x]):s}, -Q1(a){var s=a.w -if(s===6||s===7)return A.Q1(a.x) -return s===11||s===12}, -mD(a){return a.as}, -q7(a){return A.Ew(v.typeUniverse,a,!1)}, -PL(a1,a2,a3,a4){var s,r,q,p,o,n,m,l,k,j,i,h,g,f,e,d,c,b,a,a0=a2.w -switch(a0){case 5:case 1:case 2:case 3:case 4:return a2 -case 6:s=a2.x -r=A.PL(a1,s,a3,a4) -if(r===s)return a2 -return A.Bc(a1,r,!0) -case 7:s=a2.x -r=A.PL(a1,s,a3,a4) -if(r===s)return a2 -return A.LN(a1,r,!0) -case 8:q=a2.y -p=A.bZ(a1,q,a3,a4) -if(p===q)return a2 -return A.Q2(a1,a2.x,p) -case 9:o=a2.x -n=A.PL(a1,o,a3,a4) -m=a2.y -l=A.bZ(a1,m,a3,a4) -if(n===o&&l===m)return a2 -return A.ap(a1,n,l) -case 10:k=a2.x -j=a2.y -i=A.bZ(a1,j,a3,a4) -if(i===j)return a2 -return A.oP(a1,k,i) -case 11:h=a2.x -g=A.PL(a1,h,a3,a4) -f=a2.y -e=A.qT(a1,f,a3,a4) -if(g===h&&e===f)return a2 -return A.Nf(a1,g,e) -case 12:d=a2.y -a4+=d.length -c=A.bZ(a1,d,a3,a4) -o=a2.x -n=A.PL(a1,o,a3,a4) -if(c===d&&n===o)return a2 -return A.DS(a1,n,c,!0) -case 13:b=a2.x -if(b") -for(r=1;r=0)p+=" "+r[q];++q}return p+"})"}, -b(a1,a2,a3){var s,r,q,p,o,n,m,l,k,j,i,h,g,f,e,d,c,b,a=", ",a0=null -if(a3!=null){s=a3.length -if(a2==null)a2=A.j([],t.s) -else a0=a2.length -r=a2.length -for(q=s;q>0;--q)a2.push("T"+(r+q)) -for(p=t.X,o="<",n="",q=0;q0){c+=b+"[" -for(b="",q=0;q0){c+=b+"{" -for(b="",q=0;q "+d}, -d(a,b){var s,r,q,p,o,n,m=a.w -if(m===5)return"erased" -if(m===2)return"dynamic" -if(m===3)return"void" -if(m===1)return"Never" -if(m===4)return"any" -if(m===6){s=a.x -r=A.d(s,b) -q=s.w -return(q===11||q===12?"("+r+")":r)+"?"}if(m===7)return"FutureOr<"+A.d(a.x,b)+">" -if(m===8){p=A.o(a.x) -o=a.y -return o.length>0?p+("<"+A.m(o,b)+">"):p}if(m===10)return A.k(a,b) -if(m===11)return A.b(a,b,null) -if(m===12)return A.b(a.x,b,a.y) -if(m===13){n=a.x -return b[b.length-1-n]}return"?"}, -o(a){var s=v.mangledGlobalNames[a] -if(s!=null)return s -return"minified:"+a}, -Qo(a,b){var s=a.tR[b] -for(;typeof s=="string";)s=a.tR[s] -return s}, -ai(a,b){var s,r,q,p,o,n=a.eT,m=n[b] -if(m==null)return A.Ew(a,b,!1) -else if(typeof m=="number"){s=m -r=A.mZ(a,5,"#") -q=A.vU(s) -for(p=0;p0)p+="<"+A.Ux(c)+">" -s=a.eC.get(p) -if(s!=null)return s -r=new A.Jc(null,null) -r.w=8 -r.x=b -r.y=c -if(c.length>0)r.c=c[0] -r.as=p -q=A.BD(a,r) -a.eC.set(p,q) -return q}, -ap(a,b,c){var s,r,q,p,o,n -if(b.w===9){s=b.x -r=b.y.concat(c)}else{r=c -s=b}q=s.as+(";<"+A.Ux(r)+">") -p=a.eC.get(q) -if(p!=null)return p -o=new A.Jc(null,null) -o.w=9 -o.x=s -o.y=r -o.as=q -n=A.BD(a,o) -a.eC.set(q,n) -return n}, -oP(a,b,c){var s,r,q="+"+(b+"("+A.Ux(c)+")"),p=a.eC.get(q) -if(p!=null)return p -s=new A.Jc(null,null) -s.w=10 -s.x=b -s.y=c -s.as=q -r=A.BD(a,s) -a.eC.set(q,r) -return r}, -Nf(a,b,c){var s,r,q,p,o,n=b.as,m=c.a,l=m.length,k=c.b,j=k.length,i=c.c,h=i.length,g="("+A.Ux(m) -if(j>0){s=l>0?",":"" -g+=s+"["+A.Ux(k)+"]"}if(h>0){s=l>0?",":"" -g+=s+"{"+A.S4(i)+"}"}r=n+(g+")") -q=a.eC.get(r) -if(q!=null)return q -p=new A.Jc(null,null) -p.w=11 -p.x=b -p.y=c -p.as=r -o=A.BD(a,p) -a.eC.set(r,o) -return o}, -DS(a,b,c,d){var s,r=b.as+("<"+A.Ux(c)+">"),q=a.eC.get(r) -if(q!=null)return q -s=A.hw(a,b,c,r,d) -a.eC.set(r,s) -return s}, -hw(a,b,c,d,e){var s,r,q,p,o,n,m,l -if(e){s=c.length -r=A.vU(s) -for(q=0,p=0;p0){n=A.PL(a,b,r,0) -m=A.bZ(a,c,r,0) -return A.DS(a,n,m,c!==m)}}l=new A.Jc(null,null) -l.w=12 -l.x=b -l.y=c -l.as=d -return A.BD(a,l)}, -ow(a,b,c,d){return{u:a,e:b,r:c,s:[],p:0,n:d}}, -eT(a){var s,r,q,p,o,n,m,l=a.r,k=a.s -for(s=l.length,r=0;r=48&&q<=57)r=A.Al(r+1,q,l,k) -else if((((q|32)>>>0)-97&65535)<26||q===95||q===36||q===124)r=A.R8(a,r,l,k,!1) -else if(q===46)r=A.R8(a,r,l,k,!0) -else{++r -switch(q){case 44:break -case 58:k.push(!1) -break -case 33:k.push(!0) -break -case 59:k.push(A.KQ(a.u,a.e,k.pop())) -break -case 94:k.push(A.Hc(a.u,k.pop())) -break -case 35:k.push(A.mZ(a.u,5,"#")) -break -case 64:k.push(A.mZ(a.u,2,"@")) -break -case 126:k.push(A.mZ(a.u,3,"~")) -break -case 60:k.push(a.p) -a.p=k.length -break -case 62:A.rD(a,k) -break -case 38:A.I3(a,k) -break -case 63:p=a.u -k.push(A.Bc(p,A.KQ(p,a.e,k.pop()),a.n)) -break -case 47:p=a.u -k.push(A.LN(p,A.KQ(p,a.e,k.pop()),a.n)) -break -case 40:k.push(-3) -k.push(a.p) -a.p=k.length -break -case 41:A.Mt(a,k) -break -case 91:k.push(a.p) -a.p=k.length -break -case 93:o=k.splice(a.p) -A.cH(a.u,a.e,o) -a.p=k.pop() -k.push(o) -k.push(-1) -break -case 123:k.push(a.p) -a.p=k.length -break -case 125:o=k.splice(a.p) -A.Be(a.u,a.e,o) -a.p=k.pop() -k.push(o) -k.push(-2) -break -case 43:n=l.indexOf("(",r) -k.push(l.substring(r,n)) -k.push(-4) -k.push(a.p) -a.p=k.length -r=n+1 -break -default:throw"Bad character "+q}}}m=k.pop() -return A.KQ(a.u,a.e,m)}, -Al(a,b,c,d){var s,r,q=b-48 -for(s=c.length;a=48&&r<=57))break -q=q*10+(r-48)}d.push(q) -return a}, -R8(a,b,c,d,e){var s,r,q,p,o,n,m=b+1 -for(s=c.length;m>>0)-97&65535)<26||r===95||r===36||r===124))q=r>=48&&r<=57 -else q=!0 -if(!q)break}}p=c.substring(b,m) -if(e){s=a.u -o=a.e -if(o.w===9)o=o.x -n=A.Qo(s,o.x)[p] -if(n==null)A.v('No "'+p+'" in "'+A.mD(o)+'"') -d.push(A.cE(s,o,n))}else d.push(p) -return m}, -rD(a,b){var s,r=a.u,q=A.oU(a,b),p=b.pop() -if(typeof p=="string")b.push(A.Q2(r,p,q)) -else{s=A.KQ(r,a.e,p) -switch(s.w){case 11:b.push(A.DS(r,s,q,a.n)) -break -default:b.push(A.ap(r,s,q)) -break}}}, -Mt(a,b){var s,r,q,p=a.u,o=b.pop(),n=null,m=null -if(typeof o=="number")switch(o){case-1:n=b.pop() -break -case-2:m=b.pop() -break -default:b.push(o) -break}else b.push(o) -s=A.oU(a,b) -o=b.pop() -switch(o){case-3:o=b.pop() -if(n==null)n=p.sEA -if(m==null)m=p.sEA -r=A.KQ(p,a.e,o) -q=new A.ET() -q.a=s -q.b=n -q.c=m -b.push(A.Nf(p,r,q)) -return -case-4:b.push(A.oP(p,b.pop(),s)) -return -default:throw A.L(A.hV("Unexpected state under `()`: "+A.I(o)))}}, -I3(a,b){var s=b.pop() -if(0===s){b.push(A.mZ(a.u,1,"0&")) -return}if(1===s){b.push(A.mZ(a.u,4,"1&")) -return}throw A.L(A.hV("Unexpected extended operation "+A.I(s)))}, -oU(a,b){var s=b.splice(a.p) -A.cH(a.u,a.e,s) -a.p=b.pop() -return s}, -KQ(a,b,c){if(typeof c=="string")return A.Q2(a,c,a.sEA) -else if(typeof c=="number"){b.toString -return A.TV(a,b,c)}else return c}, -cH(a,b,c){var s,r=c.length -for(s=0;sn)return!1 -m=n-o -l=s.b -k=r.b -j=l.length -i=k.length -if(o+j=d)return!1 -a1=f[b] -b+=3 -if(a00?new Array(q):v.typeUniverse.sEA -for(o=0;o0?new Array(a):v.typeUniverse.sEA}, -Jc:function Jc(a,b){var _=this -_.a=a -_.b=b -_.r=_.f=_.d=_.c=null -_.w=0 -_.as=_.Q=_.z=_.y=_.x=null}, -ET:function ET(){this.c=this.b=this.a=null}, -lY:function lY(a){this.a=a}, -u9:function u9(){}, -iM:function iM(a){this.a=a}, -vL(a,b){var s=a[b] -return s===a?null:s}, -a8(a,b,c){if(c==null)a[b]=a -else a[b]=c}, -a0(){var s=Object.create(null) -A.a8(s,"",s) -delete s[""] -return s}, -EF(a,b,c){return A.dJ(a,new A.N5(b.C("@<0>").Kq(c).C("N5<1,2>")))}, -C(a,b){return new A.N5(a.C("@<0>").Kq(b).C("N5<1,2>"))}, -nO(a){var s,r -if(A.ks(a))return"{...}" -s=new A.Rn("") -try{r={} -$.Qu.push(a) -s.a+="{" -r.a=!0 -a.aN(0,new A.mN(r,s)) -s.a+="}"}finally{$.Qu.pop()}r=s.a -return r.charCodeAt(0)==0?r:r}, -k6:function k6(){}, -YF:function YF(a){var _=this -_.a=0 -_.e=_.d=_.c=_.b=null -_.$ti=a}, -Ni:function Ni(a,b){this.a=a -this.$ti=b}, -t3:function t3(a,b,c){var _=this -_.a=a -_.b=b -_.c=0 -_.d=null -_.$ti=c}, -F:function F(){}, -il:function il(){}, -mN:function mN(a,b){this.a=a -this.b=b}, -Uk:function Uk(){}, -wI:function wI(){}, -Zi:function Zi(){}, -u5:function u5(){}, -E3:function E3(){}, -Rw:function Rw(a){this.b=0 -this.c=a}, -QA(a,b){var s=A.Hp(a,b) -if(s!=null)return s -throw A.L(A.rr(a,null,null))}, -O8(a,b,c){var s,r,q -if(a<0||a>4294967295)A.v(A.TE(a,0,4294967295,"length",null)) -s=A.j(new Array(a),c.C("p<0>")) -s.$flags=1 -r=s -if(a!==0&&b!=null)for(q=0;q")) -for(s=a.length,r=0;r=s)return"" -return A.fw(a,b,s)}, -nu(a){return new A.VR(a,A.v4(a,!1,!0,!1,!1,""))}, -vg(a,b,c){var s=J.IT(b) -if(!s.G())return a -if(c.length===0){do a+=A.I(s.gl()) -while(s.G())}else{a+=A.I(s.gl()) -for(;s.G();)a=a+c+A.I(s.gl())}return a}, -eP(a,b,c,d){var s,r,q,p,o,n="0123456789ABCDEF" -if(c===B.xM){s=$.z4() -s=s.b.test(b)}else s=!1 -if(s)return b -r=B.Qk.W(b) -for(s=r.length,q=0,p="";q>>4&15]+n[o&15]}return p.charCodeAt(0)==0?p:p}, -tS(a){var s,r,q -if(!$.Ob())return A.yf(a) -s=new URLSearchParams() -a.aN(0,new A.bp(s)) -r=s.toString() -q=r.length -if(q>0&&r[q-1]==="=")r=B.xB.Nj(r,0,q-1) -return r.replace(/=&|\*|%7E/g,b=>b==="=&"?"&":b==="*"?"%2A":"~")}, -h(a){if(typeof a=="number"||A.y(a)||a==null)return J.n(a) -if(typeof a=="string")return JSON.stringify(a) -return A.i(a)}, -hV(a){return new A.C6(a)}, -q(a){return new A.AT(!1,null,null,a)}, -TE(a,b,c,d,e){return new A.bJ(b,c,!0,a,d,"Invalid value")}, -jB(a,b,c){if(0>a||a>c)throw A.L(A.TE(a,0,c,"start",null)) -if(b!=null){if(a>b||b>c)throw A.L(A.TE(b,a,c,"end",null)) -return b}return c}, -k1(a,b){if(a<0)throw A.L(A.TE(a,0,null,b,null)) -return a}, -xF(a,b,c,d){return new A.eY(b,!0,a,d,"Index out of range")}, -SY(a){return new A.ds(a)}, -a4(a){return new A.UV(a)}, -rr(a,b,c){return new A.aE(a,b,c)}, -Sd(a,b,c){var s,r -if(A.ks(a)){if(b==="("&&c===")")return"(...)" -return b+"..."+c}s=A.j([],t.s) -$.Qu.push(a) -try{A.Vr(a,s)}finally{$.Qu.pop()}r=A.vg(b,s,", ")+c -return r.charCodeAt(0)==0?r:r}, -x(a,b,c){var s,r -if(A.ks(a))return b+"..."+c -s=new A.Rn(b) -$.Qu.push(a) -try{r=s -r.a=A.vg(r.a,a,", ")}finally{$.Qu.pop()}s.a+=c -r=s.a -return r.charCodeAt(0)==0?r:r}, -Vr(a,b){var s,r,q,p,o,n,m,l=a.gkz(a),k=0,j=0 -while(!0){if(!(k<80||j<3))break -if(!l.G())return -s=A.I(l.gl()) -b.push(s) -k+=s.length+2;++j}if(!l.G()){if(j<=5)return -r=b.pop() -q=b.pop()}else{p=l.gl();++j -if(!l.G()){if(j<=4){b.push(A.I(p)) -return}r=A.I(p) -q=b.pop() -k+=r.length+2}else{o=l.gl();++j -for(;l.G();p=o,o=n){n=l.gl();++j -if(j>100){while(!0){if(!(k>75&&j>3))break -k-=b.pop().length+2;--j}b.push("...") -return}}q=A.I(p) -r=A.I(o) -k+=r.length+q.length+4}}if(j>b.length+2){k+=5 -m="..."}else m=null -while(!0){if(!(k>80&&b.length>3))break -k-=b.pop().length+2 -if(m==null){k+=5 -m="..."}}if(m!=null)b.push(m) -b.push(q) -b.push(r)}, -f5(a,b,c,d){var s -if(B.zt===c){s=B.jn.gi(a) -b=J.Nu(b) -return A.qL(A.yc(A.yc($.t8(),s),b))}if(B.zt===d){s=B.jn.gi(a) -b=J.Nu(b) -c=J.Nu(c) -return A.qL(A.yc(A.yc(A.yc($.t8(),s),b),c))}s=B.jn.gi(a) -b=J.Nu(b) -c=J.Nu(c) -d=J.Nu(d) -d=A.qL(A.yc(A.yc(A.yc(A.yc($.t8(),s),b),c),d)) -return d}, -Hh(a,b,c){var s,r,q,p,o,n,m="IPv4 address should contain exactly 4 parts",l="each part must be in the range 0..255",k=new A.cS(a),j=new Uint8Array(4) -for(s=b,r=s,q=0;s9)k.$2("invalid character",s)}else{if(q===3)k.$2(m,s) -o=A.QA(B.xB.Nj(a,r,s),null) -if(o>255)k.$2(l,r) -n=q+1 -j[q]=o -r=s+1 -q=n}}if(q!==3)k.$2(m,c) -o=A.QA(B.xB.Nj(a,r,c),null) -if(o>255)k.$2(l,r) -j[q]=o -return j}, -Xh(a,b,c){var s -if(b===c)throw A.L(A.rr("Empty IP address",a,b)) -if(a.charCodeAt(b)===118){s=A.lN(a,b,c) -if(s!=null)throw A.L(s) -return!1}A.eg(a,b,c) -return!0}, -lN(a,b,c){var s,r,q,p,o="Missing hex-digit in IPvFuture address";++b -for(s=b;!0;s=r){if(s=97&&p<=102)continue -if(q===46){if(r-1===b)return new A.aE(o,a,r) -s=r -break}return new A.aE("Unexpected character",a,r-1)}if(s-1===b)return new A.aE(o,a,s) -return new A.aE("Missing '.' in IPvFuture address",a,s)}if(s===c)return new A.aE("Missing address in IPvFuture address, host, cursor",null,null) -for(;!0;){if((u.b.charCodeAt(a.charCodeAt(s))&16)!==0){++s -if(s>>0) -s.push((k[2]<<8|k[3])>>>0)}if(p){if(s.length>7)d.$2("an address with a wildcard must have less than 7 parts",e)}else if(s.length!==8)d.$2("an address without a wildcard must contain exactly 8 parts",e) -j=new Uint8Array(16) -for(l=s.length,i=9-l,r=0,h=0;r=b&&s=b&&s=p){if(i==null)i=new A.Rn("") -if(r=o){if(q==null)q=new A.Rn("") -if(r")).h(0,"/") -if(q.length===0){if(s)return"/"}else if(r&&!B.xB.v(q,"/"))q="/"+q -return A.Jr(q,e,f)}, -Jr(a,b,c){var s=b.length===0 -if(s&&!c&&!B.xB.v(a,"/")&&!B.xB.v(a,"\\"))return A.wF(a,!s||c) -return A.xe(a)}, -le(a,b,c,d){return A.tS(d)}, -yf(a){var s={},r=new A.Rn("") -s.a="" -a.aN(0,new A.fq(new A.IP(s,r))) -s=r.a -return s.charCodeAt(0)==0?s:s}, -tG(a,b,c){return null}, -rv(a,b,c){var s,r,q,p,o,n=b+2 -if(n>=a.length)return"%" -s=a.charCodeAt(b+1) -r=a.charCodeAt(n) -q=A.oo(s) -p=A.oo(r) -if(q<0||p<0)return"%" -o=q*16+p -if(o<127&&(u.b.charCodeAt(o)&1)!==0)return A.Lw(c&&65<=o&&90>=o?(o|32)>>>0:o) -if(s>=97||r>=97)return B.xB.Nj(a,b,b+3).toUpperCase() -return null}, -zX(a){var s,r,q,p,o,n="0123456789ABCDEF" -if(a<=127){s=new Uint8Array(3) -s[0]=37 -s[1]=n.charCodeAt(a>>>4) -s[2]=n.charCodeAt(a&15)}else{if(a>2047)if(a>65535){r=240 -q=4}else{r=224 -q=3}else{r=192 -q=2}s=new Uint8Array(3*q) -for(p=0;--q,q>=0;r=128){o=B.jn.bf(a,6*q)&63|r -s[p]=37 -s[p+1]=n.charCodeAt(o>>>4) -s[p+2]=n.charCodeAt(o&15) -p+=3}}return A.HM(s)}, -PI(a,b,c,d,e,f){var s=A.Ul(a,b,c,d,e,f) -return s==null?B.xB.Nj(a,b,c):s}, -Ul(a,b,c,d,e,f){var s,r,q,p,o,n,m,l,k,j=null,i=u.b -for(s=!e,r=b,q=r,p=j;r=2&&A.Et(a.charCodeAt(0)))for(s=1;s127||(u.b.charCodeAt(r)&8)===0)break}return a}, -Et(a){var s=a|32 -return 97<=s&&s<=122}, -bp:function bp(a){this.a=a}, -Ge:function Ge(){}, -C6:function C6(a){this.a=a}, -E:function E(){}, -AT:function AT(a,b,c,d){var _=this -_.a=a -_.b=b -_.c=c -_.d=d}, -bJ:function bJ(a,b,c,d,e,f){var _=this -_.e=a -_.f=b -_.a=c -_.b=d -_.c=e -_.d=f}, -eY:function eY(a,b,c,d,e){var _=this -_.f=a -_.a=b -_.b=c -_.c=d -_.d=e}, -ub:function ub(a){this.a=a}, -ds:function ds(a){this.a=a}, -lj:function lj(a){this.a=a}, -UV:function UV(a){this.a=a}, -k5:function k5(){}, -aE:function aE(a,b,c){this.a=a -this.b=b -this.c=c}, -cX:function cX(){}, -c8:function c8(){}, -a:function a(){}, -Rn:function Rn(a){this.a=a}, -cS:function cS(a){this.a=a}, -VC:function VC(a){this.a=a}, -JT:function JT(a,b){this.a=a -this.b=b}, -Dn:function Dn(a,b,c,d,e,f,g){var _=this -_.a=a -_.b=b -_.c=c -_.d=d -_.e=e -_.f=f -_.r=g -_.y=_.w=$}, -RZ:function RZ(){}, -IP:function IP(a,b){this.a=a -this.b=b}, -fq:function fq(a){this.a=a}, -K(a,b,c){if(c>=1)return a.$1(b) -return a.$0()}, -m6(a){return a==null||A.y(a)||typeof a=="number"||typeof a=="string"||t.U.b(a)||t.E.b(a)||t.e.b(a)||t.O.b(a)||t.D.b(a)||t.k.b(a)||t.v.b(a)||t.B.b(a)||t.q.b(a)||t.J.b(a)||t.Y.b(a)}, -Pe(a){if(A.m6(a))return a -return new A.Pb(new A.YF(t.A)).$1(a)}, -Pb:function Pb(a){this.a=a}, -lM:function lM(){this.a=$}, -YE:function YE(){}, -hy(a){if(a==null)return null -return new A.TZ(a)}, -TZ:function TZ(a){this.a=a}, -E2(){var s,r,q,p,o=v.G,n=o.document.querySelectorAll("pre > code[data-dartpad]:only-child"),m=t.N,l=A.C(m,m) -o=o.window -m=new A.e(l) -if(typeof m=="function")A.v(A.q("Attempting to rewrap a JS function.")) -s=function(a,b){return function(c){return a(b,c,arguments.length)}}(A.K,m) -s[$.w()]=m -o.addEventListener("message",s) -for(o=t.m,r=0;r").Kq(c).C("A8<1,2>"))}, -h(a,b){var s,r=A.O8(a.length,"",t.N) -for(s=0;s0)return a[s-1] -throw A.L(A.Wp())}, -"["(a){return A.x(a,"[","]")}, -gkz(a){return new J.D(a,a.length,A.t6(a).C("D<1>"))}, -gi(a){return A.eQ(a)}, -gB(a){return a.length}, -$ibQ:1, -$icX:1, -$izM:1} -J.B.prototype={ -R(a){var s,r,q -if(!Array.isArray(a))return null -s=a.$flags|0 -if((s&4)!==0)r="const, " -else if((s&2)!==0)r="unmodifiable, " -else r=(s&1)!==0?"fixed, ":"" -q="Instance of '"+A.l(a)+"'" -if(r==="")return q -return q+" ("+r+"length: "+a.length+")"}} -J.Po.prototype={} -J.D.prototype={ -gl(){var s=this.d -return s==null?this.$ti.c.a(s):s}, -G(){var s,r=this,q=r.a,p=q.length -if(r.b!==p)throw A.L(A.lk(q)) -s=r.c -if(s>=p){r.d=null -return!1}r.d=q[s] -r.c=s+1 -return!0}} -J.qI.prototype={ -"["(a){if(a===0&&1/a<0)return"-0.0" -else return""+a}, -gi(a){var s,r,q,p,o=a|0 -if(a===o)return o&536870911 -s=Math.abs(a) -r=Math.log(s)/0.6931471805599453|0 -q=Math.pow(2,r) -p=s<1?s/q:q/s -return((p*9007199254740992|0)+(p*3542243181176521|0))*599197+r*1259&536870911}, -P(a,b){var s -if(a>0)s=this.p(a,b) -else{s=b>31?31:b -s=a>>s>>>0}return s}, -bf(a,b){if(0>b)throw A.L(A.tL(b)) -return this.p(a,b)}, -p(a,b){return b>31?0:a>>>b}, -gbx(a){return A.Kx(t.H)}, -$iCP:1} -J.im.prototype={ -gbx(a){return A.Kx(t.S)}, -$iy5:1, -$iKN:1} -J.kD.prototype={ -gbx(a){return A.Kx(t.i)}, -$iy5:1} -J.Dr.prototype={ -Y(a,b,c){var s -if(c<0||c>a.length)throw A.L(A.TE(c,0,a.length,null,null)) -s=c+b.length -if(s>a.length)return!1 -return b===a.substring(c,s)}, -v(a,b){return this.Y(a,b,0)}, -Nj(a,b,c){return a.substring(b,A.jB(b,c,a.length))}, -yn(a,b){return this.Nj(a,b,null)}, -OF(a){var s,r=a.trimEnd(),q=r.length -if(q===0)return r -s=q-1 -if(r.charCodeAt(s)!==133)return r -return r.substring(0,J.c1(r,s))}, -Ix(a,b){var s,r -if(0>=b)return"" -if(b===1||a.length===0)return a -if(b!==b>>>0)throw A.L(B.Eq) -for(s=a,r="";!0;){if((b&1)===1)r=s+r -b=b>>>1 -if(b===0)break -s+=s}return r}, -K(a,b,c){var s -if(c<0||c>a.length)throw A.L(A.TE(c,0,a.length,null,null)) -s=a.indexOf(b,c) -return s}, -M(a,b){return this.K(a,b,0)}, -I(a,b){return A.m2(a,b,0)}, -"["(a){return a}, -gi(a){var s,r,q -for(s=a.length,r=0,q=0;q>6}r=r+((r&67108863)<<3)&536870911 -r^=r>>11 -return r+((r&16383)<<15)&536870911}, -gbx(a){return A.Kx(t.N)}, -$iy5:1, -$iqU:1} -A.SH.prototype={ -"["(a){return"LateInitializationError: "+this.a}} -A.zl.prototype={} -A.bQ.prototype={} -A.aL.prototype={ -gkz(a){var s=this -return new A.a7(s,s.gB(s),A.Lh(s).C("a7"))}, -h(a,b){var s,r,q,p=this,o=p.gB(p) -if(b.length!==0){if(o===0)return"" -s=A.I(p.F(0,0)) -if(o!==p.gB(p))throw A.L(A.a4(p)) -for(r=s,q=1;q").Kq(c).C("A8<1,2>"))}} -A.a7.prototype={ -gl(){var s=this.d -return s==null?this.$ti.c.a(s):s}, -G(){var s,r=this,q=r.a,p=J.U6(q),o=p.gB(q) -if(r.b!==o)throw A.L(A.a4(q)) -s=r.c -if(s>=o){r.d=null -return!1}r.d=p.F(q,s);++r.c -return!0}} -A.i1.prototype={ -gkz(a){var s=this.a -return new A.MH(s.gkz(s),this.b,A.Lh(this).C("MH<1,2>"))}} -A.xy.prototype={$ibQ:1} -A.MH.prototype={ -G(){var s=this,r=s.b -if(r.G()){s.a=s.c.$1(r.gl()) -return!0}s.a=null -return!1}, -gl(){var s=this.a -return s==null?this.$ti.y[1].a(s):s}} -A.A8.prototype={ -gB(a){return J.Hm(this.a)}, -F(a,b){return this.b.$1(J.GA(this.a,b))}} -A.SU.prototype={} -A.S0.prototype={$r:"+code,id(1,2)",$s:1} -A.rY.prototype={} -A.t.prototype={ -"["(a){var s=this.constructor,r=s==null?null:s.name -return"Closure '"+A.H(r==null?"unknown":r)+"'"}, -gKu(){return this}, -$C:"$1", -$R:1, -$D:null} -A.E1.prototype={$C:"$2",$R:2} -A.lc.prototype={} -A.zx.prototype={ -"["(a){var s=this.$static_name -if(s==null)return"Closure of unknown static method" -return"Closure '"+A.H(s)+"'"}} -A.rT.prototype={ -DN(a,b){if(b==null)return!1 -if(this===b)return!0 -if(!(b instanceof A.rT))return!1 -return this.$_target===b.$_target&&this.a===b.a}, -gi(a){return(A.CU(this.a)^A.eQ(this.$_target))>>>0}, -"["(a){return"Closure '"+this.$_name+"' of "+("Instance of '"+A.l(this.a)+"'")}} -A.Eq.prototype={ -"["(a){return"RuntimeError: "+this.a}} -A.N5.prototype={ -gvc(){return new A.Gp(this,this.$ti.C("Gp<1>"))}, -WH(a,b){var s,r,q,p,o=null -if(typeof b=="string"){s=this.b -if(s==null)return o -r=s[b] -q=r==null?o:r.b -return q}else if(typeof b=="number"&&(b&0x3fffffff)===b){p=this.c -if(p==null)return o -r=p[b] -q=r==null?o:r.b -return q}else return this.aa(b)}, -aa(a){var s,r,q=this.d -if(q==null)return null -s=q[J.Nu(a)&1073741823] -r=this.X(s,a) -if(r<0)return null -return s[r].b}, -t(a,b,c){var s,r,q,p,o,n,m=this -if(typeof b=="string"){s=m.b -m.m(s==null?m.b=m.A():s,b,c)}else if(typeof b=="number"&&(b&0x3fffffff)===b){r=m.c -m.m(r==null?m.c=m.A():r,b,c)}else{q=m.d -if(q==null)q=m.d=m.A() -p=J.Nu(b)&1073741823 -o=q[p] -if(o==null)q[p]=[m.O(b,c)] -else{n=m.X(o,b) -if(n>=0)o[n].b=c -else o.push(m.O(b,c))}}}, -j(a,b){var s=this.H4(this.b,b) -return s}, -aN(a,b){var s=this,r=s.e,q=s.r -for(;r!=null;){b.$2(r.a,r.b) -if(q!==s.r)throw A.L(A.a4(s)) -r=r.c}}, -m(a,b,c){var s=a[b] -if(s==null)a[b]=this.O(b,c) -else s.b=c}, -H4(a,b){var s -if(a==null)return null -s=a[b] -if(s==null)return null -this.GS(s) -delete a[b] -return s.b}, -S(){this.r=this.r+1&1073741823}, -O(a,b){var s,r=this,q=new A.vh(a,b) -if(r.e==null)r.e=r.f=q -else{s=r.f -s.toString -q.d=s -r.f=s.c=q}++r.a -r.S() -return q}, -GS(a){var s=this,r=a.d,q=a.c -if(r==null)s.e=q -else r.c=q -if(q==null)s.f=r -else q.d=r;--s.a -s.S()}, -X(a,b){var s,r -if(a==null)return-1 -s=a.length -for(r=0;r"]=s -delete s[""] -return s}} -A.vh.prototype={} -A.Gp.prototype={ -gkz(a){var s=this.a -return new A.N6(s,s.r,s.e)}} -A.N6.prototype={ -gl(){return this.d}, -G(){var s,r=this,q=r.a -if(r.b!==q.r)throw A.L(A.a4(q)) -s=r.c -if(s==null){r.d=null -return!1}else{r.d=s.a -r.c=s.c -return!0}}} -A.dC.prototype={ -$1(a){return this.a(a)}} -A.wN.prototype={ -$2(a,b){return this.a(a,b)}} -A.VX.prototype={ -$1(a){return this.a(a)}} -A.M.prototype={ -"["(a){return this.k(!1)}, -k(a){var s,r,q,p,o,n=this.D(),m=this.n(),l=(a?"Record ":"")+"(" -for(s=n.length,r="",q=0;q0;){--q;--s -k[q]=r[s]}}k=A.PW(k,!1,t.K) -k.$flags=3 -return k}} -A.B7.prototype={ -n(){return[this.a,this.b]}, -DN(a,b){if(b==null)return!1 -return b instanceof A.B7&&this.$s===b.$s&&J.cf(this.a,b.a)&&J.cf(this.b,b.b)}, -gi(a){return A.f5(this.$s,this.a,this.b,B.zt)}} -A.VR.prototype={ -"["(a){return"RegExp/"+this.a+"/"+this.b.flags}} -A.WZ.prototype={ -gbx(a){return B.lb}, -$iy5:1, -$iI2:1} -A.eH.prototype={} -A.df.prototype={ -gbx(a){return B.LV}, -$iy5:1, -$iWy:1} -A.b0.prototype={ -gB(a){return a.length}, -$iXj:1} -A.Dg.prototype={$ibQ:1,$icX:1,$izM:1} -A.DV.prototype={$ibQ:1,$icX:1,$izM:1} -A.zU.prototype={ -gbx(a){return B.Vr}, -$iy5:1, -$ioI:1} -A.K8.prototype={ -gbx(a){return B.mB}, -$iy5:1, -$imJ:1} -A.xj.prototype={ -gbx(a){return B.x9}, -$iy5:1, -$irF:1} -A.dE.prototype={ -gbx(a){return B.G3}, -$iy5:1, -$iX6:1} -A.Zc.prototype={ -gbx(a){return B.xg}, -$iy5:1, -$iZX:1} -A.wf.prototype={ -gbx(a){return B.Ry}, -$iy5:1, -$iHS:1} -A.Pq.prototype={ -gbx(a){return B.zo}, -$iy5:1, -$iPz:1} -A.eE.prototype={ -gbx(a){return B.xU}, -gB(a){return a.length}, -$iy5:1, -$izt:1} -A.V6.prototype={ -gbx(a){return B.iY}, -gB(a){return a.length}, -$iy5:1, -$in6:1} -A.RG.prototype={} -A.vX.prototype={} -A.WB.prototype={} -A.VS.prototype={} -A.Jc.prototype={ -C(a){return A.cE(v.typeUniverse,this,a)}, -Kq(a){return A.v5(v.typeUniverse,this,a)}} -A.ET.prototype={} -A.lY.prototype={ -"["(a){return A.d(this.a,null)}} -A.u9.prototype={ -"["(a){return this.a}} -A.iM.prototype={} -A.k6.prototype={ -gvc(){return new A.Ni(this,this.$ti.C("Ni<1>"))}, -x4(a){var s,r -if(typeof a=="string"&&a!=="__proto__"){s=this.b -return s==null?!1:s[a]!=null}else if(typeof a=="number"&&(a&1073741823)===a){r=this.c -return r==null?!1:r[a]!=null}else return this.KY(a)}, -KY(a){var s=this.d -if(s==null)return!1 -return this.DF(this.e1(s,a),a)>=0}, -WH(a,b){var s,r,q -if(typeof b=="string"&&b!=="__proto__"){s=this.b -r=s==null?null:A.vL(s,b) -return r}else if(typeof b=="number"&&(b&1073741823)===b){q=this.c -r=q==null?null:A.vL(q,b) -return r}else return this.c8(b)}, -c8(a){var s,r,q=this.d -if(q==null)return null -s=this.e1(q,a) -r=this.DF(s,a) -return r<0?null:s[r+1]}, -t(a,b,c){var s,r,q,p=this,o=p.d -if(o==null)o=p.d=A.a0() -s=A.CU(b)&1073741823 -r=o[s] -if(r==null){A.a8(o,s,[b,c]);++p.a -p.e=null}else{q=p.DF(r,b) -if(q>=0)r[q+1]=c -else{r.push(b,c);++p.a -p.e=null}}}, -aN(a,b){var s,r,q,p,o,n=this,m=n.Cf() -for(s=m.length,r=n.$ti.y[1],q=0;q"))}} -A.t3.prototype={ -gl(){var s=this.d -return s==null?this.$ti.c.a(s):s}, -G(){var s=this,r=s.b,q=s.c,p=s.a -if(r!==p.e)throw A.L(A.a4(p)) -else if(q>=r.length){s.d=null -return!1}else{s.d=r[q] -s.c=q+1 -return!0}}} -A.F.prototype={ -gkz(a){return new A.a7(a,a.length,A.z(a).C("a7"))}, -F(a,b){return a[b]}, -E2(a,b,c){return new A.A8(a,b,A.z(a).C("@").Kq(c).C("A8<1,2>"))}, -"["(a){return A.x(a,"[","]")}} -A.il.prototype={ -aN(a,b){var s,r,q,p -for(s=this.gvc(),s=s.gkz(s),r=A.Lh(this).y[1];s.G();){q=s.gl() -p=this.WH(0,q) -b.$2(q,p==null?r.a(p):p)}}, -"["(a){return A.nO(this)}} -A.mN.prototype={ -$2(a,b){var s,r=this.a -if(!r.a)this.b.a+=", " -r.a=!1 -r=this.b -s=A.I(a) -r.a=(r.a+=s)+": " -s=A.I(b) -r.a+=s}} -A.Uk.prototype={} -A.wI.prototype={} -A.Zi.prototype={} -A.u5.prototype={} -A.E3.prototype={ -W(a){var s,r,q,p=A.jB(0,null,a.length) -if(p===0)return new Uint8Array(0) -s=p*3 -r=new Uint8Array(s) -q=new A.Rw(r) -if(q.T(a,0,p)!==p)q.H() -return new Uint8Array(r.subarray(0,A.rM(0,q.b,s)))}} -A.Rw.prototype={ -H(){var s=this,r=s.c,q=s.b,p=s.b=q+1 -r.$flags&2&&A.cW(r) -r[q]=239 -q=s.b=p+1 -r[p]=191 -s.b=q+1 -r[q]=189}, -O6(a,b){var s,r,q,p,o=this -if((b&64512)===56320){s=65536+((a&1023)<<10)|b&1023 -r=o.c -q=o.b -p=o.b=q+1 -r.$flags&2&&A.cW(r) -r[q]=s>>>18|240 -q=o.b=p+1 -r[p]=s>>>12&63|128 -p=o.b=q+1 -r[q]=s>>>6&63|128 -o.b=p+1 -r[p]=s&63|128 -return!0}else{o.H() -return!1}}, -T(a,b,c){var s,r,q,p,o,n,m,l,k=this -if(b!==c&&(a.charCodeAt(c-1)&64512)===55296)--c -for(s=k.c,r=s.$flags|0,q=s.length,p=b;p=q)break -k.b=n+1 -r&2&&A.cW(s) -s[n]=o}else{n=o&64512 -if(n===55296){if(k.b+4>q)break -m=p+1 -if(k.O6(o,a.charCodeAt(m)))p=m}else if(n===56320){if(k.b+3>q)break -k.H()}else if(o<=2047){n=k.b -l=n+1 -if(l>=q)break -k.b=l -r&2&&A.cW(s) -s[n]=o>>>6|192 -k.b=l+1 -s[l]=o&63|128}else{n=k.b -if(n+2>=q)break -l=k.b=n+1 -r&2&&A.cW(s) -s[n]=o>>>12|224 -n=k.b=l+1 -s[l]=o>>>6&63|128 -k.b=n+1 -s[n]=o&63|128}}}return p}} -A.bp.prototype={ -$2(a,b){var s,r -if(typeof b=="string")this.a.set(a,b) -else if(b==null)this.a.set(a,"") -else for(s=J.IT(b),r=this.a;s.G();){b=s.gl() -if(typeof b=="string")r.append(a,b) -else if(b==null)r.append(a,"") -else A.ra(b)}}} -A.Ge.prototype={} -A.C6.prototype={ -"["(a){var s=this.a -if(s!=null)return"Assertion failed: "+A.h(s) -return"Assertion failed"}} -A.E.prototype={} -A.AT.prototype={ -gZ(){return"Invalid argument"+(!this.a?"(s)":"")}, -gN(){return""}, -"["(a){var s=this,r=s.c,q=r==null?"":" ("+r+")",p=s.d,o=p==null?"":": "+p,n=s.gZ()+q+o -if(!s.a)return n -return n+s.gN()+": "+A.h(s.gE())}, -gE(){return this.b}} -A.bJ.prototype={ -gE(){return this.b}, -gZ(){return"RangeError"}, -gN(){var s,r=this.e,q=this.f -if(r==null)s=q!=null?": Not less than or equal to "+A.I(q):"" -else if(q==null)s=": Not greater than or equal to "+A.I(r) -else if(q>r)s=": Not in inclusive range "+A.I(r)+".."+A.I(q) -else s=qe.length -else s=!1 -if(s)f=null -if(f==null){if(e.length>78)e=B.xB.Nj(e,0,75)+"..." -return g+"\n"+e}for(r=1,q=0,p=!1,o=0;o1?g+(" (at line "+r+", character "+(f-q+1)+")\n"):g+(" (at character "+(f+1)+")\n") -m=e.length -for(o=f;o78){k="..." -if(f-q<75){j=q+75 -i=q}else{if(m-f<75){i=m-75 -j=m -k=""}else{i=f-36 -j=f+36}l="..."}}else{j=m -i=q -k=""}return g+l+B.xB.Nj(e,i,j)+k+"\n"+B.xB.Ix(" ",f-i+l.length)+"^\n"}else return f!=null?g+(" (at offset "+A.I(f)+")"):g}} -A.cX.prototype={ -E2(a,b,c){return A.K1(this,b,A.Lh(this).C("cX.E"),c)}, -gB(a){var s,r=this.gkz(this) -for(s=0;r.G();)++s -return s}, -F(a,b){var s,r -A.k1(b,"index") -s=this.gkz(this) -for(r=b;s.G();){if(r===0)return s.gl();--r}throw A.L(A.xF(b,b-r,this,"index"))}, -"["(a){return A.Sd(this,"(",")")}} -A.c8.prototype={ -gi(a){return A.a.prototype.gi.call(this,0)}, -"["(a){return"null"}} -A.a.prototype={$ia:1, -DN(a,b){return this===b}, -gi(a){return A.eQ(this)}, -"["(a){return"Instance of '"+A.l(this)+"'"}, -gbx(a){return A.RW(this)}, -toString(){return this["["](this)}} -A.Rn.prototype={ -"["(a){var s=this.a -return s.charCodeAt(0)==0?s:s}} -A.cS.prototype={ -$2(a,b){throw A.L(A.rr("Illegal IPv4 address, "+a,this.a,b))}} -A.VC.prototype={ -$2(a,b){throw A.L(A.rr("Illegal IPv6 address, "+a,this.a,b))}} -A.JT.prototype={ -$2(a,b){var s -if(b-a>4)this.a.$2("an IPv6 part can only contain a maximum of 4 hex digits",a) -s=A.QA(B.xB.Nj(this.b,a,b),16) -if(s<0||s>65535)this.a.$2("each part must be in the range of `0x0..0xFFFF`",a) -return s}} -A.Dn.prototype={ -gL(){var s,r,q,p,o=this,n=o.w -if(n===$){s=o.a -r=s.length!==0?s+":":"" -q=o.c -p=q==null -if(!p||s==="file"){s=r+"//" -r=o.b -if(r.length!==0)s=s+r+"@" -if(!p)s+=q -r=o.d -if(r!=null)s=s+":"+A.I(r)}else s=r -s+=o.e -r=o.f -if(r!=null)s=s+"?"+r -r=o.r -if(r!=null)s=s+"#"+r -n!==$&&A.kL() -n=o.w=s.charCodeAt(0)==0?s:s}return n}, -gi(a){var s,r=this,q=r.y -if(q===$){s=B.xB.gi(r.gL()) -r.y!==$&&A.kL() -r.y=s -q=s}return q}, -gq(){var s=this.c -if(s==null)return"" -if(B.xB.v(s,"[")&&!B.xB.Y(s,"v",1))return B.xB.Nj(s,1,s.length-1) -return s}, -gtp(){var s=this.d -return s==null?A.wK(this.a):s}, -"["(a){return this.gL()}, -DN(a,b){var s,r,q,p,o,n=this -if(b==null)return!1 -if(n===b)return!0 -s=!1 -if(b instanceof A.Dn)if(n.a===b.a)if(n.c!=null===(b.c!=null))if(n.b===b.b)if(n.gq()===b.gq())if(n.gtp()===b.gtp())if(n.e===b.e){r=n.f -q=r==null -p=b.f -o=p==null -if(!q===!o){if(q)r="" -if(r===(o?"":p)){r=n.r -q=r==null -p=b.r -o=p==null -if(!q===!o){s=q?"":r -s=s===(o?"":p)}}}}return s}} -A.RZ.prototype={ -$1(a){return A.eP(64,a,B.xM,!1)}} -A.IP.prototype={ -$2(a,b){var s=this.b,r=this.a -s.a+=r.a -r.a="&" -r=A.eP(1,a,B.xM,!0) -r=s.a+=r -if(b!=null&&b.length!==0){s.a=r+"=" -r=A.eP(1,b,B.xM,!0) -s.a+=r}}} -A.fq.prototype={ -$2(a,b){var s,r -if(b==null||typeof b=="string")this.a.$2(a,b) -else for(s=J.IT(b),r=this.a;s.G();)r.$2(a,s.gl())}} -A.Pb.prototype={ -$1(a){var s,r,q,p -if(A.m6(a))return a -s=this.a -if(s.x4(a))return s.WH(0,a) -if(a instanceof A.il){r={} -s.t(0,a,r) -for(s=a.gvc(),s=s.gkz(s);s.G();){q=s.gl() -r[q]=this.$1(a.WH(0,q))}return r}else if(t.V.b(a)){p=[] -s.t(0,a,p) -B.Nm.FV(p,J.M1(a,this,t.z)) -return p}else return a}} -A.lM.prototype={} -A.YE.prototype={ -U(){this.a=Math.max(18,5)}, -W(a){var s,r,q,p,o,n,m,l,k,j,i,h,g,f -if(!B.xB.I(a,"&"))return a -s=new A.Rn("") -for(r=a.length,q=0;!0;){p=B.xB.K(a,"&",q) -if(p===-1){s.a+=B.xB.yn(a,q) -break}o=s.a+=B.xB.Nj(a,q,p) -n=this.a -n===$&&A.Q4() -m=B.xB.Nj(a,p,Math.min(r,p+n)) -if(m.length>4&&m.charCodeAt(1)===35){l=B.xB.M(m,";") -if(l!==-1){k=m.charCodeAt(2)===120 -j=B.xB.Nj(m,k?3:2,l) -i=A.Hp(j,k?16:10) -if(i==null)i=-1 -if(i!==-1){s.a=o+A.Lw(i) -q=p+(l+1) -continue}}}g=0 -while(!0){if(!(g<268)){q=p -h=!1 -break}f=B.uu[g] -if(B.xB.v(m,f)){s.a+=B.nO[g] -q=p+f.length -h=!0 -break}++g}if(!h){s.a+="&";++q}}r=s.a -return r.charCodeAt(0)==0?r:r}} -A.TZ.prototype={} -A.e.prototype={ -$1(a){var s,r,q,p,o,n,m=null,l=a.data,k=t.m,j=m,i=!1 -if(k.b(l)){s=l.type -r=s -if(r!=null){q=s==null?A.Bt(s):s -p=l.sender -r=p -if(r!=null){j=p==null?A.Bt(p):p -i=q==="ready"}}}if(i){i=this.a -o=i.WH(0,j) -if(o!=null){n=v.G.document.getElementById(j) -if(n==null)n=k.a(n) -k=A.hy(n.contentWindow) -if(k!=null){r=t.N -r=A.Pe(A.EF(["sourceCode",o,"type","sourceCode"],r,r)) -k.a.postMessage(r,"*")}i.j(0,j)}}}};(function aliases(){var s=J.u0.prototype -s.u=s["["]})();(function inheritance(){var s=hunkHelpers.mixin,r=hunkHelpers.inherit,q=hunkHelpers.inheritMany -r(A.a,null) -q(A.a,[A.FK,J.vB,A.rY,J.D,A.Ge,A.zl,A.cX,A.a7,A.MH,A.SU,A.M,A.t,A.il,A.vh,A.N6,A.VR,A.Jc,A.ET,A.lY,A.t3,A.F,A.Uk,A.wI,A.Rw,A.k5,A.aE,A.c8,A.Rn,A.Dn,A.TZ]) -q(J.vB,[J.yE,J.CD,J.MF,J.rQ,J.Dw,J.qI,J.Dr]) -q(J.MF,[J.u0,J.p,A.WZ,A.eH]) -q(J.u0,[J.iC,J.kd,J.c5]) -r(J.B,A.rY) -r(J.Po,J.p) -q(J.qI,[J.im,J.kD]) -q(A.Ge,[A.SH,A.Eq,A.u9,A.C6,A.E,A.AT,A.ub,A.ds,A.lj,A.UV]) -q(A.cX,[A.bQ,A.i1]) -q(A.bQ,[A.aL,A.Gp,A.Ni]) -r(A.xy,A.i1) -r(A.A8,A.aL) -r(A.B7,A.M) -r(A.S0,A.B7) -q(A.t,[A.E1,A.lc,A.dC,A.VX,A.RZ,A.Pb,A.e]) -q(A.lc,[A.zx,A.rT]) -q(A.il,[A.N5,A.k6]) -q(A.E1,[A.wN,A.mN,A.bp,A.cS,A.VC,A.JT,A.IP,A.fq]) -q(A.eH,[A.df,A.b0]) -q(A.b0,[A.RG,A.WB]) -r(A.vX,A.RG) -r(A.Dg,A.vX) -r(A.VS,A.WB) -r(A.DV,A.VS) -q(A.Dg,[A.zU,A.K8]) -q(A.DV,[A.xj,A.dE,A.Zc,A.wf,A.Pq,A.eE,A.V6]) -r(A.iM,A.u9) -r(A.YF,A.k6) -r(A.Zi,A.Uk) -r(A.u5,A.Zi) -q(A.wI,[A.E3,A.YE]) -q(A.AT,[A.bJ,A.eY]) -r(A.lM,A.YE) -s(A.RG,A.F) -s(A.vX,A.SU) -s(A.WB,A.F) -s(A.VS,A.SU)})() -var v={G:typeof self!="undefined"?self:globalThis,typeUniverse:{eC:new Map(),tR:{},eT:{},tPV:{},sEA:[]},mangledGlobalNames:{KN:"int",CP:"double",lf:"num",qU:"String",a2:"bool",c8:"Null",zM:"List",a:"Object",T8:"Map"},mangledNames:{},types:[],interceptorsByTag:null,leafTags:null,arrayRti:Symbol("$ti"),rttc:{"2;code,id":(a,b)=>c=>c instanceof A.S0&&a.b(c.a)&&b.b(c.b)}} -A.xb(v.typeUniverse,JSON.parse('{"iC":"u0","kd":"u0","c5":"u0","yE":{"y5":[]},"CD":{"y5":[]},"MF":{"vm":[]},"u0":{"vm":[]},"p":{"zM":["1"],"bQ":["1"],"vm":[],"cX":["1"]},"B":{"rY":[]},"Po":{"p":["1"],"zM":["1"],"bQ":["1"],"vm":[],"cX":["1"]},"qI":{"CP":[]},"im":{"CP":[],"KN":[],"y5":[]},"kD":{"CP":[],"y5":[]},"Dr":{"qU":[],"y5":[]},"bQ":{"cX":["1"]},"aL":{"bQ":["1"],"cX":["1"]},"i1":{"cX":["2"],"cX.E":"2"},"xy":{"i1":["1","2"],"bQ":["2"],"cX":["2"],"cX.E":"2"},"A8":{"aL":["2"],"bQ":["2"],"cX":["2"],"aL.E":"2","cX.E":"2"},"N5":{"il":["1","2"]},"Gp":{"bQ":["1"],"cX":["1"],"cX.E":"1"},"WZ":{"vm":[],"I2":[],"y5":[]},"eH":{"vm":[]},"df":{"Wy":[],"vm":[],"y5":[]},"b0":{"Xj":["1"],"vm":[]},"Dg":{"F":["CP"],"zM":["CP"],"Xj":["CP"],"bQ":["CP"],"vm":[],"cX":["CP"]},"DV":{"F":["KN"],"zM":["KN"],"Xj":["KN"],"bQ":["KN"],"vm":[],"cX":["KN"]},"zU":{"oI":[],"F":["CP"],"zM":["CP"],"Xj":["CP"],"bQ":["CP"],"vm":[],"cX":["CP"],"y5":[],"F.E":"CP"},"K8":{"mJ":[],"F":["CP"],"zM":["CP"],"Xj":["CP"],"bQ":["CP"],"vm":[],"cX":["CP"],"y5":[],"F.E":"CP"},"xj":{"rF":[],"F":["KN"],"zM":["KN"],"Xj":["KN"],"bQ":["KN"],"vm":[],"cX":["KN"],"y5":[],"F.E":"KN"},"dE":{"X6":[],"F":["KN"],"zM":["KN"],"Xj":["KN"],"bQ":["KN"],"vm":[],"cX":["KN"],"y5":[],"F.E":"KN"},"Zc":{"ZX":[],"F":["KN"],"zM":["KN"],"Xj":["KN"],"bQ":["KN"],"vm":[],"cX":["KN"],"y5":[],"F.E":"KN"},"wf":{"HS":[],"F":["KN"],"zM":["KN"],"Xj":["KN"],"bQ":["KN"],"vm":[],"cX":["KN"],"y5":[],"F.E":"KN"},"Pq":{"Pz":[],"F":["KN"],"zM":["KN"],"Xj":["KN"],"bQ":["KN"],"vm":[],"cX":["KN"],"y5":[],"F.E":"KN"},"eE":{"zt":[],"F":["KN"],"zM":["KN"],"Xj":["KN"],"bQ":["KN"],"vm":[],"cX":["KN"],"y5":[],"F.E":"KN"},"V6":{"n6":[],"F":["KN"],"zM":["KN"],"Xj":["KN"],"bQ":["KN"],"vm":[],"cX":["KN"],"y5":[],"F.E":"KN"},"k6":{"il":["1","2"]},"YF":{"k6":["1","2"],"il":["1","2"]},"Ni":{"bQ":["1"],"cX":["1"],"cX.E":"1"},"zM":{"bQ":["1"],"cX":["1"]},"ZX":{"zM":["KN"],"bQ":["KN"],"cX":["KN"]},"n6":{"zM":["KN"],"bQ":["KN"],"cX":["KN"]},"zt":{"zM":["KN"],"bQ":["KN"],"cX":["KN"]},"rF":{"zM":["KN"],"bQ":["KN"],"cX":["KN"]},"HS":{"zM":["KN"],"bQ":["KN"],"cX":["KN"]},"X6":{"zM":["KN"],"bQ":["KN"],"cX":["KN"]},"Pz":{"zM":["KN"],"bQ":["KN"],"cX":["KN"]},"oI":{"zM":["CP"],"bQ":["CP"],"cX":["CP"]},"mJ":{"zM":["CP"],"bQ":["CP"],"cX":["CP"]}}')) -A.FF(v.typeUniverse,JSON.parse('{"bQ":1,"SU":1,"N6":1,"b0":1,"Uk":2,"wI":2}')) -var u={b:"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\u03f6\x00\u0404\u03f4 \u03f4\u03f6\u01f6\u01f6\u03f6\u03fc\u01f4\u03ff\u03ff\u0584\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u05d4\u01f4\x00\u01f4\x00\u0504\u05c4\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u0400\x00\u0400\u0200\u03f7\u0200\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u03ff\u0200\u0200\u0200\u03f7\x00"} -var t=(function rtii(){var s=A.q7 -return{J:s("I2"),Y:s("Wy"),Q:s("bQ<@>"),B:s("oI"),q:s("mJ"),Z:s("EH"),O:s("rF"),k:s("X6"),U:s("ZX"),V:s("cX<@>"),f:s("p"),s:s("p"),b:s("p<@>"),t:s("p"),T:s("CD"),m:s("vm"),g:s("c5"),p:s("Xj<@>"),j:s("zM<@>"),P:s("c8"),K:s("a"),L:s("VY"),F:s("+()"),N:s("qU"),R:s("y5"),D:s("HS"),v:s("Pz"),e:s("zt"),E:s("n6"),o:s("kd"),A:s("YF"),y:s("a2"),i:s("CP"),z:s("@"),S:s("KN"),W:s("b8?"),X:s("a?"),w:s("qU?"),u:s("a2?"),I:s("CP?"),x:s("KN?"),n:s("lf?"),H:s("lf")}})();(function constants(){var s=hunkHelpers.makeConstList -B.Ok=J.vB.prototype -B.Nm=J.p.prototype -B.jn=J.im.prototype -B.xB=J.Dr.prototype -B.DG=J.c5.prototype -B.Ub=J.MF.prototype -B.ZQ=J.iC.prototype -B.vB=J.kd.prototype -B.O4=function getTagFallback(o) { - var s = Object.prototype.toString.call(o); - return s.substring(8, s.length - 1); -} -B.Yq=function() { - var toStringFunction = Object.prototype.toString; - function getTag(o) { - var s = toStringFunction.call(o); - return s.substring(8, s.length - 1); - } - function getUnknownTag(object, tag) { - if (/^HTML[A-Z].*Element$/.test(tag)) { - var name = toStringFunction.call(object); - if (name == "[object Object]") return null; - return "HTMLElement"; - } - } - function getUnknownTagGenericBrowser(object, tag) { - if (object instanceof HTMLElement) return "HTMLElement"; - return getUnknownTag(object, tag); - } - function prototypeForTag(tag) { - if (typeof window == "undefined") return null; - if (typeof window[tag] == "undefined") return null; - var constructor = window[tag]; - if (typeof constructor != "function") return null; - return constructor.prototype; - } - function discriminator(tag) { return null; } - var isBrowser = typeof HTMLElement == "function"; - return { - getTag: getTag, - getUnknownTag: isBrowser ? getUnknownTagGenericBrowser : getUnknownTag, - prototypeForTag: prototypeForTag, - discriminator: discriminator }; -} -B.wb=function(getTagFallback) { - return function(hooks) { - if (typeof navigator != "object") return hooks; - var userAgent = navigator.userAgent; - if (typeof userAgent != "string") return hooks; - if (userAgent.indexOf("DumpRenderTree") >= 0) return hooks; - if (userAgent.indexOf("Chrome") >= 0) { - function confirm(p) { - return typeof window == "object" && window[p] && window[p].name == p; - } - if (confirm("Window") && confirm("HTMLElement")) return hooks; - } - hooks.getTag = getTagFallback; - }; -} -B.KU=function(hooks) { - if (typeof dartExperimentalFixupGetTag != "function") return hooks; - hooks.getTag = dartExperimentalFixupGetTag(hooks.getTag); -} -B.dk=function(hooks) { - if (typeof navigator != "object") return hooks; - var userAgent = navigator.userAgent; - if (typeof userAgent != "string") return hooks; - if (userAgent.indexOf("Firefox") == -1) return hooks; - var getTag = hooks.getTag; - var quickMap = { - "BeforeUnloadEvent": "Event", - "DataTransfer": "Clipboard", - "GeoGeolocation": "Geolocation", - "Location": "!Location", - "WorkerMessageEvent": "MessageEvent", - "XMLDocument": "!Document"}; - function getTagFirefox(o) { - var tag = getTag(o); - return quickMap[tag] || tag; - } - hooks.getTag = getTagFirefox; -} -B.xi=function(hooks) { - if (typeof navigator != "object") return hooks; - var userAgent = navigator.userAgent; - if (typeof userAgent != "string") return hooks; - if (userAgent.indexOf("Trident/") == -1) return hooks; - var getTag = hooks.getTag; - var quickMap = { - "BeforeUnloadEvent": "Event", - "DataTransfer": "Clipboard", - "HTMLDDElement": "HTMLElement", - "HTMLDTElement": "HTMLElement", - "HTMLPhraseElement": "HTMLElement", - "Position": "Geoposition" - }; - function getTagIE(o) { - var tag = getTag(o); - var newTag = quickMap[tag]; - if (newTag) return newTag; - if (tag == "Object") { - if (window.DataView && (o instanceof window.DataView)) return "DataView"; - } - return tag; - } - function prototypeForTagIE(tag) { - var constructor = window[tag]; - if (constructor == null) return null; - return constructor.prototype; - } - hooks.getTag = getTagIE; - hooks.prototypeForTag = prototypeForTagIE; -} -B.fQ=function(hooks) { - var getTag = hooks.getTag; - var prototypeForTag = hooks.prototypeForTag; - function getTagFixed(o) { - var tag = getTag(o); - if (tag == "Document") { - if (!!o.xmlVersion) return "!Document"; - return "!HTMLDocument"; - } - return tag; - } - function prototypeForTagFixed(tag) { - if (tag == "Document") return null; - return prototypeForTag(tag); - } - hooks.getTag = getTagFixed; - hooks.prototypeForTag = prototypeForTagFixed; -} -B.i7=function(hooks) { return hooks; } - -B.Eq=new A.k5() -B.zt=new A.zl() -B.xM=new A.u5() -B.Qk=new A.E3() -B.nO=s(["`","\xa0","\xb4","|","\xb7","\xa8","\xb1","\xb7","_","\xae","\xb8","\n","\xa6","%","*","{","|",".","}","\xfd","\xa4","\xfa","\xf5","=","\xf9","@","\xf8","\xb1","\xf7","[","$","\xb7","]","\xd3","_","\xbc","\xbd","\xbe","\xbf","\xc0","\xc1","\xc3","\xf3","\xc8","\xc9","\xcc","\xcd","\xd1","\xd2","\xd5","\xd8","\xd9","\xda","\xdd","\xe0","\xe1","\xe3","\xe7","\xe8","\xe9","\xec","\xed","\xf1","\xf2","\xc7","\xea","\xb4","\xa4","\xf4","\xa6","\xf3","\xa3","\xf2","\xf9","\xf1",":","\xab","\xee","\xf8","\xed","\xfe","\xfd","\xf7","\xc8","\xec","\xaf","\xa1","\xb1","\xe9","\xdf","\xe8","\xb5","\xe7","\xb7","\xb8","\xfb","\xe6",",","\xbb","\xfa","\xbc","\xbd","?","\xbe","\xbf","\xc0","\xc1","\xc2","\xc3","\xc5","\xc5","\xc6","\xe5","\xde","\xc9","\xca","\xcc","\xe3","\xcd","\xce","\xe2","`","\xd1","\xd2","\xe1","\xd3","\xd4","f","\xd5","\xe0","\xd7","\xf5","\xd8","\xd9","\xda","\xdb","\xdd","\xc7","\xaf","\xb2","[",";","\xb3","\xc2","\\","+","\xc4","\xe5","\xf4","\xb4","\xc5","\xa7","\xc6","\xa9","\xb5","]","\xd7","\xff","\xb6","\xa2","\xca","\xcb","\xe4","\xfe","\xa0","\xfc","\xf6","\xfb","\xce","\xcf","}","\xe2","\xa9","\xb8","\xa1","'","\xb9","\xaa","\xba","\xef","\xd4","\xa3","\xbb","\xd6","\xab","\xeb",">","(",'"',"{","\xbd",")","\xee","\xea","\xdb","\xdc","\xdf","|","!","<","\xde",'"',"\xe6","=","\xd6",'"',"\xff","\xf6","\xd0","\xcf","&","\xcb","\xe4","&","\xc4","\xb9","\xba","*","\xb6","\xa0","#","\xb3","\xb2","\xad","\xfc","\xf7","\xeb","\xb0","\xaf","\xae","\xae","\xdc","\xac","\xaa","\xef","\xf0","\xa9","\xa9","\xa8","\xa2","\xa8","\xa8","\xa7","/",'"',"\xa5","\t","^","\xd0","\xb1","\xb0","\xae","\xae","\xad","\xac","\xa8","\xa5",">",">","<","<","&","&","\xf0",">",">","<","<"],t.s) -B.uu=s(["`"," ","´","|","·","¨","±","·","_","®","¸"," ","¦","%","*","{","|",".","}","ý","¤","ú","õ","=","ù","@","ø","±","÷","[","$","·","]","Ó","_","¼","½","¾","¿","À","Á","Ã","ó","È","É","Ì","Í","Ñ","Ò","Õ","Ø","Ù","Ú","Ý","à","á","ã","ç","è","é","ì","í","ñ","ò","Ç","ê","´","¤","ô","¦","ó","£","ò","ù","ñ",":","«","î","ø","í","þ","ý","÷","È","ì","¯","¡","±","é","ß","è","µ","ç","·","¸","û","æ",",","»","ú","¼","½","?","¾","¿","À","Á","Â","Ã","Å","Å","Æ","å","Þ","É","Ê","Ì","ã","Í","Î","â","`","Ñ","Ò","á","Ó","Ô","fj","Õ","à","×","õ","Ø","Ù","Ú","Û","Ý","Ç","¯","²","[",";","³","Â","\","+","Ä","å","ô","´","Å","§","Æ","©","µ","]","×","ÿ","¶","¢","Ê","Ë","ä","þ"," ","ü","ö","û","Î","Ï","}","â","©","¸","¡","'","¹","ª","º","ï","Ô","£","»","Ö","«","ë",">⃒","(",""","{","½",")","î","ê","Û","Ü","ß","|","!","<⃒","Þ",""","æ","=⃥","Ö",""","ÿ","ö","Ð","Ï","&","Ë","ä","&","Ä","¹","º","*","¶"," ","#","³","²","­","ü","÷","ë","°","¯","®","®","Ü","¬","ª","ï","ð","©","©","¨","¢","¨","¨","§","/",""","¥"," ","^","Ð","±","°","®","®","­","¬","¨","¥",">",">","<","<","&","&","ð",">",">","<","<"],t.s) -B.lb=A.xq("I2") -B.LV=A.xq("Wy") -B.Vr=A.xq("oI") -B.mB=A.xq("mJ") -B.x9=A.xq("rF") -B.G3=A.xq("X6") -B.xg=A.xq("ZX") -B.h0=A.xq("a") -B.Ry=A.xq("HS") -B.zo=A.xq("Pz") -B.xU=A.xq("zt") -B.iY=A.xq("n6")})();(function staticFields(){$.zm=null -$.Qu=A.j([],t.f) -$.xu=null -$.i0=null -$.Hb=null -$.NF=null -$.TX=null -$.x7=null -$.nw=null -$.vv=null -$.Bv=null -$.Bi=A.j([],A.q7("p?>")) -$.j1=0})();(function lazyInitializers(){var s=hunkHelpers.lazyFinal -s($,"fa","w",()=>A.Yg("_$dart_dartClosure")) -s($,"hJ","u",()=>A.j([new J.B()],A.q7("p"))) -s($,"mf","z4",()=>A.nu("^[\\-\\.0-9A-Z_a-z~]*$")) -s($,"Cc","Ob",()=>typeof URLSearchParams=="function") -s($,"X0","t8",()=>A.CU(B.h0)) -s($,"Zj","Ww",()=>{var r=new A.lM() -r.U() -return r})})();(function nativeSupport(){!function(){var s=function(a){var m={} -m[a]=1 -return Object.keys(hunkHelpers.convertToFastObject(m))[0]} -v.getIsolateTag=function(a){return s("___dart_"+a+v.isolateTag)} -var r="___dart_isolate_tags_" -var q=Object[r]||(Object[r]=Object.create(null)) -var p="_ZxYxX" -for(var o=0;;o++){var n=s(p+"_"+o+"_") -if(!(n in q)){q[n]=1 -v.isolateTag=n -break}}v.dispatchPropertyName=v.getIsolateTag("dispatch_record")}() -hunkHelpers.setOrUpdateInterceptorsByTag({ArrayBuffer:A.WZ,ArrayBufferView:A.eH,DataView:A.df,Float32Array:A.zU,Float64Array:A.K8,Int16Array:A.xj,Int32Array:A.dE,Int8Array:A.Zc,Uint16Array:A.wf,Uint32Array:A.Pq,Uint8ClampedArray:A.eE,CanvasPixelArray:A.eE,Uint8Array:A.V6}) -hunkHelpers.setOrUpdateLeafTags({ArrayBuffer:true,ArrayBufferView:false,DataView:true,Float32Array:true,Float64Array:true,Int16Array:true,Int32Array:true,Int8Array:true,Uint16Array:true,Uint32Array:true,Uint8ClampedArray:true,CanvasPixelArray:true,Uint8Array:false}) -A.b0.$nativeSuperclassTag="ArrayBufferView" -A.RG.$nativeSuperclassTag="ArrayBufferView" -A.vX.$nativeSuperclassTag="ArrayBufferView" -A.Dg.$nativeSuperclassTag="ArrayBufferView" -A.WB.$nativeSuperclassTag="ArrayBufferView" -A.VS.$nativeSuperclassTag="ArrayBufferView" -A.DV.$nativeSuperclassTag="ArrayBufferView"})() -Function.prototype.$0=function(){return this()} -Function.prototype.$1=function(a){return this(a)} -Function.prototype.$2=function(a,b){return this(a,b)} -Function.prototype.$1$1=function(a){return this(a)} -convertAllToFastObject(w) -convertToFastObject($);(function(a){if(typeof document==="undefined"){a(null) -return}if(typeof document.currentScript!="undefined"){a(document.currentScript) -return}var s=document.scripts -function onLoad(b){for(var q=0;q 0 || - this.tags.size > 0; - }, - // Takes a Set, and returns a filtered Set - filter: function (resources) { - const resourcesToShow = new Set(); - let filteredResources = []; - if (this.hasFilters()) { - for (const resource of resources) { - const tags = resource.tags.join(' ').toLowerCase(); - const selectedFilterTags = Array.from(filters.tags); - const matchesTags = selectedFilterTags.some(t => { - return tags.includes(t) - }); - - const type = resource.type.toLowerCase(); - const selectedTypes = Array.from(filters.type); - const matchesTypes = selectedTypes.some(t => { - return t === type - }); - - if (matchesTags || matchesTypes) { - filteredResources.push(resource); - } - } - } else { - filteredResources = resources; - } - - for (const resource of filteredResources) { - const tags = resource.tags.join('').toLowerCase(); - const type = resource.type.toLowerCase(); - const description = resource.description.toLowerCase(); - const name = resource.name.toLowerCase(); - - if (name.includes(this.searchTerm) || - tags.toLowerCase().includes(this.searchTerm) || - type.includes(this.searchTerm) || - description.includes(this.searchTerm) - ) { - resourcesToShow.add(resource.name); - } - } - - return resourcesToShow; - }, - clear: function () { - this.type.clear(); - this.tags.clear(); - this.searchTerm = ''; - } -} - -function _setupResourceFilters() { - // index the resource metadata - const resourceGrid = document.getElementById('all-resources-grid'); - if (!resourceGrid) return; - const resourceCards = resourceGrid.querySelectorAll('.card'); - const resourcesInfo = _setupResourceInfo(resourceCards); - - // sets up the resource count element that says "Showing x / y" below the search bar. - const allResourcesCount = document.getElementById('total-resource-card-count'); - allResourcesCount.textContent = (resourcesInfo.length).toString(); - - // set up search bar interaction - const searchSection = document.getElementById('resource-search-group'); - const searchInput = searchSection.querySelector('.search-wrapper input'); - searchInput.addEventListener('input', _ => { - filters.searchTerm = searchInput.value.toLowerCase(); - filterResources(); - }); - - // set up checkbox interaction handling - const filterSection = document.getElementById('resource-filter-group'); - const allCheckboxes = filterSection.querySelectorAll('input'); - allCheckboxes.forEach(checkbox => { - _setupFilterChange(checkbox, filterResources); - }); - - // Clear filters button - const clearFiltersButton = document.getElementById("clear-resource-index-filters"); - clearFiltersButton.addEventListener('click', _ => { - filters.clear(); - searchInput.value = ''; - filterResources(); - allCheckboxes.forEach(box => { - box.checked = false; - }) - }); - - function toggleClearFiltersButton() { - clearFiltersButton.disabled = !(filters.hasFilters() || filters.searchTerm > 0); - } - - function filterResources() { - toggleClearFiltersButton(); - const resourcesToShow = filters.filter(resourcesInfo); - resourceCards.forEach(card => { - const resourceName = card.id; - if (resourcesToShow.has(resourceName)) { - card.classList.remove('hidden'); - } else { - card.classList.add('hidden'); - } - }); - const resourcesCount = document.getElementById('displayed-resource-card-count'); - resourcesCount.textContent = resourcesToShow.size.toString(); - } - - filterResources(); -} - - -function _setUpCollapsibleFilterLists() { - const filterSidebar = document.getElementById('resource-filter-group'); - const filterGroups = filterSidebar.querySelectorAll('ul'); - const toggleButtons = filterSidebar.querySelectorAll('button'); - - toggleButtons.forEach(button => { - const id = button.id; - const correspondingUlId = "#" + id.split('-').slice(0, 2).join('-'); - const ul = filterSidebar.querySelector(correspondingUlId); - - const liCount = Array.from(ul.querySelectorAll('li')).length; - if (liCount <= 2) { - button.classList.add('hidden'); - return; - } - - button.addEventListener('click', _ => { - const nodeList = ul.querySelectorAll('li'); - const liElements = Array.from(nodeList); - const isCollapsed = ul.classList.contains('collapsed'); - const icon = button.querySelector('.material-symbols'); - const label = button.querySelector('.label'); - if (isCollapsed) { - liElements.forEach(li => li.classList.remove('hidden')); - label.textContent = 'Less'; - icon.textContent = 'expand_less'; - ul.classList.remove('collapsed'); - } else { - liElements.slice(2).forEach(li => li.classList.add('hidden')); - icon.textContent = 'expand_more'; - label.textContent = 'More'; - ul.classList.add('collapsed'); - } - }); - }); - - // Show the first few items to start. - filterGroups.forEach(ul => { - const allFiltersForGroup = ul.querySelectorAll('li'); - const initialAmountToShow = 4; - for (let filterIndex = 0; filterIndex < initialAmountToShow && filterIndex < allFiltersForGroup.length; filterIndex += 1) { - allFiltersForGroup[filterIndex].classList.remove('hidden'); - } - }); -} - -function _setupResourceInfo(resourceCards) { - const resourcesInfo = []; - resourceCards.forEach(card => { - const resourceName = card.id; - if (!resourceName) return; - const tags = card.dataset.tags.split(', ').map(t => t.toLowerCase()); - resourcesInfo.push({ - name: resourceName, - type: card.dataset.type, - tags: tags, - description: card.dataset.description, - }); - - card.addEventListener('click', async (_) => { - window.dataLayer?.push({ - 'event': 'learning_resource_index_click', - 'learning_resource_type': card.dataset.type, - 'learning_resource_title': resourceName, - }); - }); - }); - return resourcesInfo; -} - -function _setupFilterChange(checkbox, filterResources) { - const id = checkbox.id; - const filter = id.split('-')[1].toLowerCase(); - // category refers to the filter types: tags, type - const category = checkbox.dataset.category.toLowerCase(); - - checkbox.addEventListener('change', _ => { - if (checkbox.checked) { - window.dataLayer?.push({ - 'event': 'learning_resource_index_filter_selected', - 'learning_resource_filter_name': filter, - 'learning_resource_filter_type': category, - }); - switch (category) { - case 'tags': - const tagGroup = filters.resourceTagMapping[filter]; - tagGroup.forEach(tag => filters[category].add(tag)) - break; - case 'type': - const typeGroup = filters.resourceTypeMapping[filter]; - typeGroup.forEach(type => filters[category].add(type)) - break; - } - } else { - switch (category) { - case 'tags': - const tagGroup = filters.resourceTagMapping[filter]; - tagGroup.forEach(tag => filters[category].delete(tag)) - break; - case 'type': - const typeGroup = filters.resourceTypeMapping[filter]; - typeGroup.forEach(type => filters[category].delete(type)) - break; - } - } - - filterResources(); - }); -} - -// This button is only displayed on smaller screens -function _setupDropdownMenu() { - const pageContent = document.getElementById('resource-index-content'); - if (!pageContent) return; - - const filtersButton = pageContent.querySelector('.show-filters-button'); - const filtersEl = document.getElementById('resource-filter-group-wrapper') || pageContent.querySelector('.right-col'); - const openToggleCheckbox = document.getElementById('open-filter-toggle'); - - if (!filtersButton || !filtersEl) return; - - function _closeMenu() { - if (openToggleCheckbox) { - openToggleCheckbox.checked = false; - } else { - filtersEl.classList.remove('show'); - } - filtersButton.ariaExpanded = 'false'; - } - - function _openMenu() { - if (openToggleCheckbox) { - openToggleCheckbox.checked = true; - } else { - filtersEl.classList.add('show'); - } - filtersButton.ariaExpanded = 'true'; - } - - function _isMenuOpen() { - if (openToggleCheckbox) { - return openToggleCheckbox.checked; - } else { - return filtersEl.classList.contains('show'); - } - } - - filtersButton.addEventListener('click', (_) => { - if (_isMenuOpen()) { - _closeMenu(); - } else { - _openMenu(); - } - }); - - document.addEventListener('keydown', (event) => { - if (event.key === 'Escape') { - _closeMenu(); - } - }); - - // Close the dropdown if anywhere not in the filters menu is. - const content = document.getElementById('all-resources-grid'); - if (content) { - content.addEventListener('click', () => { - if (_isMenuOpen()) { - _closeMenu(); - } - }); - } -} - -function shuffleElements(container) { - const elements = container.children; - for (let i = elements.length; i >= 0; i--) { - container.appendChild(elements[Math.random() * i | 0]); - } -} - -window.addEventListener('load', (_) => { - const resourceGrid = document.getElementById('all-resources-grid'); - shuffleElements(resourceGrid); -}) - - -document.onreadystatechange = () => { - if (document.readyState === "interactive" || - document.readyState === "complete") { - _setupResourceFilters(); - _setUpCollapsibleFilterLists(); - _setupDropdownMenu(); - } -} diff --git a/src/content/assets/js/main.js b/src/content/assets/js/main.js deleted file mode 100644 index 9687d5b830c..00000000000 --- a/src/content/assets/js/main.js +++ /dev/null @@ -1,614 +0,0 @@ -const _prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)'); - -function setupTheme() { - const themeMenu = document.getElementById('theme-menu'); - if (themeMenu) { - const themeButtons = themeMenu.querySelectorAll('button'); - - function updateButtonSelectedState() { - const theme = - document.body.classList.contains('auto-mode') ? 'auto' : - document.body.classList.contains('dark-mode') ? 'dark' : 'light'; - - themeButtons.forEach((button) => { - button.ariaSelected = button.dataset.theme === theme ? 'true' : 'false'; - }); - } - - themeButtons.forEach((button) => { - button.addEventListener('click', (_) => { - const newMode = `${button.dataset.theme}-mode`; - - document.body.classList.remove('auto-mode', 'dark-mode', 'light-mode'); - document.body.classList.add(newMode); - - window.localStorage.setItem('theme', newMode); - _switchToPreferenceIfAuto(); - - updateButtonSelectedState(); - }); - }); - - updateButtonSelectedState(); - } - - _prefersDarkMode.addEventListener('change', _switchToPreferenceIfAuto); -} - -function _switchToPreferenceIfAuto() { - if (document.body.classList.contains('auto-mode')) { - if (_prefersDarkMode.matches) { - document.body.classList.remove('light-mode'); - document.body.classList.add('dark-mode'); - } else { - document.body.classList.remove('dark-mode'); - document.body.classList.add('light-mode'); - } - } -} - -function setupSidenavInteractivity() { - document.getElementById('menu-toggle')?.addEventListener('click', function (e) { - document.body.classList.toggle('open_menu'); - }); - - window.addEventListener('resize', function() { - if (window.innerWidth >= 1024) { - document.body.classList.remove('open_menu'); - } - }); - - document.addEventListener('keydown', function(event) { - if (event.key === 'Escape') { - const activeElement = document.activeElement; - if (activeElement && (activeElement.id === 'menu-toggle' || activeElement.closest('#sidenav'))) { - document.body.classList.remove('open_menu'); - } - } - }); -} - -function setupCollapsibleElements() { - const toggles = document.querySelectorAll('[data-toggle="collapse"]'); - toggles.forEach(function (toggle) { - const targetSelector = toggle.getAttribute('data-target'); - if (!targetSelector) return; - const target = document.querySelector(targetSelector); - if (!target) return; - - toggle.addEventListener('click', (e) => { - if (toggle.classList.contains('collapsed')) { - toggle.classList.remove('collapsed'); - toggle.ariaExpanded = 'true'; - - target.classList.add('show'); - } else { - toggle.classList.add('collapsed'); - toggle.ariaExpanded = 'false'; - - target.classList.remove('show'); - } - - e.preventDefault(); - }); - }); -} - -/** - * Get the user's current operating system, or - * `null` if not of one "macos", "windows", "linux", or "chromeos". - * - * @returns {'macos'|'linux'|'windows'|'chromeos'|null} - */ -function getOS() { - const userAgent = window.navigator.userAgent; - if (userAgent.indexOf('Mac') !== -1) { - // macOS or iPhone - return 'macos'; - } - - if (userAgent.indexOf('Win') !== -1) { - // Windows - return 'windows'; - } - - if ((userAgent.indexOf('Linux') !== -1 || userAgent.indexOf("X11") !== -1) - && userAgent.indexOf('Android') === -1) { - // Linux, but not Android - return 'linux'; - } - - if (userAgent.indexOf('CrOS') !== -1) { - // ChromeOS - return 'chromeos'; - } - - // Anything else - return null; -} - -function scrollSidenavIntoView() { - const sidenav = document.getElementById('sidenav'); - if (!sidenav) { - return; - } - - const activeEntries = sidenav.querySelectorAll('.nav-link.active'); - if (activeEntries.length > 0) { - const activeEntry = activeEntries[activeEntries.length - 1]; - - sidenav.scrollTo({ - top: activeEntry.offsetTop - window.innerHeight / 3, - }); - } -} - -/** - * Adjusts the behavior of the table of contents (TOC) on the page. - * - * This function enables a "scrollspy" feature on the TOC, - * where the active link in the TOC is updated - * based on the currently visible section in the page. - * - * Enables a "back to top" button in the TOC header. - */ -function setupToc() { - const tocHeader = document.querySelector('#toc-side header'); - - if (tocHeader) { - tocHeader.addEventListener('click', (_) => { - _scrollToTop(); - }); - } - - function _scrollToTop() { - const distanceBetweenTop = document.documentElement.scrollTop || document.body.scrollTop; - if (distanceBetweenTop > 0) { - window.scrollTo({ top: 0, behavior: 'smooth' }); - } - } - - _setupTocActiveObserver(); - _setupInlineTocDropdown(); -} - -function _setupInlineTocDropdown() { - const inlineToc = document.getElementById('toc-top'); - if (!inlineToc) return; - - const dropdownButton = inlineToc.querySelector('.dropdown-button'); - const dropdownMenu = inlineToc.querySelector('.dropdown-content'); - if (!dropdownButton || !dropdownMenu) return; - - function _closeMenu() { - dropdownMenu.classList.remove('show'); - dropdownButton.ariaExpanded = 'false'; - } - - dropdownButton.addEventListener('click', (_) => { - if (dropdownMenu.classList.contains('show')) { - _closeMenu(); - } else { - dropdownMenu.classList.add('show'); - dropdownButton.ariaExpanded = 'true'; - } - }); - - document.addEventListener('keydown', (event) => { - if (event.key === 'Escape') { - _closeMenu(); - } - }); - - // Close the dropdown if any link in the TOC is navigated to. - inlineToc.querySelectorAll('a').forEach(tocLink => { - tocLink.addEventListener('click', (_) => { - _closeMenu(); - }); - }); - - // Close the dropdown if anywhere not in the inline TOC is clicked. - document.addEventListener('click', (event) => { - if (event.target.closest('#toc-top')) { - return; - } - _closeMenu(); - }); -} - -function _setupTocActiveObserver() { - const headings = document.querySelectorAll('article > .header-wrapper, #site-header-wrapper'); - const currentHeaderText = document.getElementById('current-header'); - - // No need to have toc scrollspy if there is only one non-title heading. - if (headings.length < 2 || currentHeaderText === null) return; - - const visibleAnchors = new Set(); - const initialHeaderText = currentHeaderText.textContent; - - const observer = new IntersectionObserver( - (entries) => { - entries.forEach(entry => { - const headingId = entry.target.querySelector('h1, h2, h3')?.id; - if (!headingId) return; - - if (entry.isIntersecting) { - visibleAnchors.add(headingId); - } else { - visibleAnchors.delete(headingId); - } - }); - - if (visibleAnchors.size > 0) { - let isFirst = true; - - // If the page title is visible, set the current header to its contents. - if (visibleAnchors.has('document-title')) { - currentHeaderText.textContent = initialHeaderText; - isFirst = false; - } - - document.querySelectorAll(`.site-toc .sidenav-item a`).forEach(tocLink => { - const headingId = tocLink.getAttribute('href')?.substring(1); - if (!headingId) return; - - const sidenavItem = tocLink.closest('.sidenav-item'); - if (!sidenavItem) return; - - if (visibleAnchors.has(headingId)) { - sidenavItem.classList.add('active'); - - if (isFirst) { - currentHeaderText.textContent = tocLink.textContent; - isFirst = false; - } - } else { - sidenavItem.classList.remove('active'); - } - }); - } - },{ rootMargin: '-80px 0px -25% 0px' }); - - headings.forEach(heading => observer.observe(heading)); -} - -function setupSearch() { - document.addEventListener('keydown', handleSearchShortcut); -} - -function handleSearchShortcut(event) { - const activeElement = document.activeElement; - if (activeElement instanceof HTMLInputElement || - activeElement instanceof HTMLTextAreaElement || - event.code !== 'Slash' - ) { - return; - } - - // If the page has a search field in the body, focus that. - const bodySearch = document.querySelector('input.gsc-input'); - // Otherwise, focus the search field in the navbar. - const searchElement = bodySearch ? bodySearch : document - .querySelector('input.search-field'); - - // If we successfully found a search field, focus that. - if (searchElement) { - searchElement.focus(); - // Prevent the initial slash from showing up in the search field. - event.preventDefault(); - } -} - -/** - * Activate the cookie notice footer. - */ -function initCookieNotice() { - const cookieKey = 'cookie-consent'; - const currentDate = Date.now(); - const existingDateString = window.localStorage.getItem(cookieKey); - if (existingDateString) { - const existingDate = parseInt(existingDateString); - if (Number.isInteger(existingDate)) { - const halfYearMs = 1000 * 60 * 60 * 24 * 180; - // If the last consent is less than 180 days old, don't show the notice. - if (currentDate - existingDate < halfYearMs) { - return; - } - } - } - - const notice = document.getElementById('cookie-notice'); - const agreeBtn = document.getElementById('cookie-consent'); - const activeClass = 'show'; - - agreeBtn.addEventListener('click', (e) => { - e.preventDefault(); - window.localStorage.setItem(cookieKey, currentDate.toString()); - notice.classList.remove(activeClass); - }); - - notice.classList.add(activeClass); -} - -// A pattern to remove terminal command markers when copying code blocks. -const terminalReplacementPattern = /^(\s*\$\s*)|(C:\\(.*)>\s*)/gm; - -function setUpCodeBlockButtons() { - const codeBlocks = - document.querySelectorAll('.code-block-body'); - - const canUseClipboard = !!navigator.clipboard; - - codeBlocks.forEach(codeBlock => { - const preElement = codeBlock.querySelector('pre'); - if (!preElement) { - return; - } - - const buttonWrapper = document.createElement('div'); - buttonWrapper.classList.add('code-inner-buttons'); - - const dartPadGistId = preElement.getAttribute('data-dartpad-id'); - if (dartPadGistId && dartPadGistId.length > 5) { - const dartPadButton = document.createElement('button'); - const innerIcon = document.createElement('span'); - - dartPadButton.title = 'Open in DartPad'; - - innerIcon.textContent = 'open_in_new'; - innerIcon.ariaHidden = 'true'; - innerIcon.classList.add('material-symbols'); - - dartPadButton.addEventListener('click', (e) => { - const codeBlockBody = e.currentTarget.parentElement; - if (codeBlockBody) { - const codePre = codeBlock.querySelector('pre'); - if (codePre) { - window.open(`https://dartpad.dev?id=${dartPadGistId}&run=true`); - } - } - }); - - dartPadButton.appendChild(innerIcon); - buttonWrapper.appendChild(dartPadButton); - } - - if (canUseClipboard) { - const copyButton = document.createElement('button'); - const innerIcon = document.createElement('span'); - - copyButton.title = 'Copy to clipboard'; - - innerIcon.textContent = 'content_copy'; - innerIcon.ariaHidden = 'true'; - innerIcon.classList.add('material-symbols'); - innerIcon.setAttribute('translate', 'no'); - - copyButton.addEventListener('click', async (e) => { - const codeBlockBody = e.currentTarget.parentElement; - if (codeBlockBody) { - const codePre = codeBlock.querySelector('pre'); - if (codePre) { - const contentToCopy = codePre.textContent - .replace(terminalReplacementPattern, ''); - if (contentToCopy && contentToCopy.length !== 0) { - await navigator.clipboard.writeText(contentToCopy); - } - e.preventDefault(); - } - } - }); - - copyButton.appendChild(innerIcon); - buttonWrapper.appendChild(copyButton); - } - - codeBlock.appendChild(buttonWrapper); - }); -} - -function setupThemeSwitcher() { - const themeSwitcher = document.getElementById('theme-switcher'); - if (!themeSwitcher) { - return; - } - - const themeSwitcherButton = themeSwitcher.querySelector('.dropdown-button'); - const themeSwitcherMenu = themeSwitcher.querySelector('#theme-menu'); - if (!themeSwitcherButton || !themeSwitcherMenu) { - return; - } - - function _closeMenusAndToggle() { - themeSwitcherMenu.classList.remove('show'); - themeSwitcherButton.ariaExpanded = 'false'; - } - - themeSwitcherButton.addEventListener('click', (_) => { - if (themeSwitcherMenu.classList.contains('show')) { - _closeMenusAndToggle(); - } else { - themeSwitcherMenu.classList.add('show'); - themeSwitcherButton.ariaExpanded = 'true'; - } - }); - - document.addEventListener('keydown', (event) => { - // If pressing the `esc` key in the menu area, close the menu. - if (event.key === 'Escape' && event.target.closest('#theme-switcher')) { - _closeMenusAndToggle(); - } - }); - - themeSwitcher.addEventListener('focusout', (e) => { - // If focus leaves the theme-switcher, hide the menu. - if (e.relatedTarget && !e.relatedTarget.closest('#theme-switcher')) { - _closeMenusAndToggle(); - } - }); - - document.addEventListener('click', (event) => { - // If not clicking inside the theme switcher, close the menu. - if (!event.target.closest('#theme-switcher')) { - _closeMenusAndToggle(); - } - }) -} - -function setupSiteSwitcher() { - const siteSwitcher = document.getElementById('site-switcher'); - - if (!siteSwitcher) { - return; - } - - const siteSwitcherButton = siteSwitcher.querySelector('.dropdown-button'); - const siteSwitcherMenu = siteSwitcher.querySelector('#site-switcher-menu'); - if (!siteSwitcherButton || !siteSwitcherMenu) { - return; - } - - function _closeMenusAndToggle() { - siteSwitcherMenu.classList.remove('show'); - siteSwitcherButton.ariaExpanded = 'false'; - } - - siteSwitcherButton.addEventListener('click', (_) => { - if (siteSwitcherMenu.classList.contains('show')) { - _closeMenusAndToggle(); - } else { - siteSwitcherMenu.classList.add('show'); - siteSwitcherButton.ariaExpanded = 'true'; - } - }); - - document.addEventListener('keydown', (event) => { - // If pressing the `esc` key in the menu area, close the menu. - if (event.key === 'Escape' && event.target.closest('#site-switcher')) { - _closeMenusAndToggle(); - } - }); - - siteSwitcher.addEventListener('focusout', (e) => { - // If focus leaves the site-switcher, hide the menu. - if (e.relatedTarget && !e.relatedTarget.closest('#site-switcher')) { - _closeMenusAndToggle(); - } - }); - - document.addEventListener('click', (event) => { - // If not clicking inside the site switcher, close the menu. - if (!event.target.closest('#site-switcher')) { - _closeMenusAndToggle(); - } - }); -} - -function setupFeedback() { - const feedbackContainer = - document.getElementById('page-feedback'); - if (!feedbackContainer) return; - - const feedbackUpButton = feedbackContainer.querySelector('#feedback-up-button'); - const feedbackDownButton = feedbackContainer.querySelector('#feedback-down-button'); - if (!feedbackUpButton || !feedbackDownButton) return; - - feedbackUpButton.addEventListener('click', (_) => { - window.dataLayer?.push({'event': 'inline_feedback', 'feedback_type': 'up'}); - - feedbackContainer.classList.add('feedback-up'); - }, { once: true }); - - feedbackDownButton.addEventListener('click', (_) => { - window.dataLayer?.push({'event': 'inline_feedback', 'feedback_type': 'down'}); - - feedbackContainer.classList.add('feedback-down'); - }, { once: true }); -} - -function setupPlatformKeys() { - const os = getOS(); - const specialKey = os === 'macos' ? 'Command' : 'Control'; - document.querySelectorAll('kbd.special-key') - .forEach(function (element) { - element.textContent = specialKey; - }); -} - -function _osNameFromId(osId) { - switch (osId) { - case 'macos': - return 'macOS'; - case 'linux': - return 'Linux'; - case 'chromeos': - return 'ChromeOS'; - default: - return 'Windows'; - } -} - -function _adjustSelectedOs(osId) { - if (!osId) return; - - const osName = _osNameFromId(osId); - const selectedOsTextSpans = document.querySelectorAll('.selected-os-text'); - selectedOsTextSpans.forEach(function (span) { - span.textContent = osName; - }); - - const osSelectors = document.querySelectorAll('.os-selector button'); - osSelectors.forEach(function (osSelector) { - if (osSelector.getAttribute('data-os') === osId) { - osSelector.classList.add('selected-card'); - } else { - osSelector.classList.remove('selected-card'); - } - }); - - document.body.classList.remove('show-macos', 'show-linux', 'show-windows', 'show-chromeos'); - document.body.classList.add(`show-${osId}`); -} - -function setupOsSelectors() { - const currentOsId = getOS() ?? 'windows'; - _adjustSelectedOs(currentOsId); - - const osSelectors = document.querySelectorAll('.os-selector'); - - for (const osSelector of osSelectors) { - const osButtons = osSelector.querySelectorAll('button'); - for (const osButton of osButtons) { - const osId = osButton.getAttribute('data-os'); - osButton.addEventListener('click', (e) => { - _adjustSelectedOs(osId); - }); - } - } -} - -function setupSite() { - setupTheme(); - scrollSidenavIntoView(); - initCookieNotice(); - - setupOsSelectors(); - setupSidenavInteractivity(); - setUpCodeBlockButtons(); - - setupSearch(); - setupSiteSwitcher(); - setupTabs(); - setupThemeSwitcher(); - - setupToc(); - setupPlatformKeys(); - setupCollapsibleElements(); - setupFeedback(); -} - -if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', setupSite); -} else { - setupSite(); -} diff --git a/src/content/assets/js/tabs.js b/src/content/assets/js/tabs.js deleted file mode 100644 index c57be8fb93a..00000000000 --- a/src/content/assets/js/tabs.js +++ /dev/null @@ -1,107 +0,0 @@ -/** Set up interactivity of tabs created with the `{% tabs %}` shortcode. */ -function setupTabs() { - _applyFromQueryParameters(); - - const tabsWrappers = document.querySelectorAll('.tabs-wrapper'); - - tabsWrappers.forEach(function (tabWrapper) { - const saveKey = tabWrapper.dataset.tabSaveKey; - const localStorageKey = `tab-save-${saveKey}`; - const tabs = tabWrapper.querySelectorAll(':scope > .nav-tabs a.nav-link'); - let tabToChangeTo; - - tabs.forEach(function (tab) { - const saveId = tab.dataset.tabSaveId; - - tab.addEventListener('click', function (event) { - event.preventDefault(); - if (saveKey && saveId) { - // If the tab wrapper and this tab have a save key and ID defined, - // switch other tabs to the tab with the same ID. - _findAndActivateTabsWithSaveId(saveKey, saveId); - localStorage.setItem(localStorageKey, saveId); - } else { - _clearActiveTabs(tabs); - _setActiveTab(tab); - } - }); - - // If a tab was previously specified as selected in local storage, - // save a reference to it that can be switched to later. - if (saveId && localStorage.getItem(localStorageKey) === saveId) { - tabToChangeTo = tab; - } - }); - - if (tabToChangeTo) { - tabToChangeTo.click(); - } else if (saveKey === 'os-archive-tabs') { - // If this tab wrapper is for the archive page, - // and no tab was retrieved from local storage, - // switch to the tab for the current OS. - const currentOperatingSystem = _getOsForArchive(); - - if (currentOperatingSystem) { - _activateTabWithSaveId(tabWrapper, currentOperatingSystem); - } - } - }); -} - -/** Apply force overrides from query parameters to saved tabs. */ -function _applyFromQueryParameters() { - const currentUrl = new URL(window.location.href); - const searchParams = currentUrl.searchParams; - const paramsToDelete = []; - - searchParams.forEach((value, key) => { - if (key.startsWith('tab-save-')) { - localStorage.setItem(key, value); - paramsToDelete.push(key); - } - }); - - paramsToDelete.forEach(key => searchParams.delete(key)); - window.history.replaceState({}, '', currentUrl.toString()); -} - -function _clearActiveTabs(tabs) { - tabs.forEach(function (tab) { - tab.classList.remove('active'); - tab.ariaSelected = 'false'; - document.getElementById(`${tab.id}-panel`)?.classList.remove('active'); - }); -} - -function _setActiveTab(tab) { - tab.classList.add('active'); - tab.ariaSelected = 'true'; - document.getElementById(`${tab.id}-panel`)?.classList.add('active'); -} - -function _findAndActivateTabsWithSaveId(saveKey, saveId) { - const tabsWrappers = document.querySelectorAll(`.tabs-wrapper[data-tab-save-key="${saveKey}"]`); - - tabsWrappers.forEach((tabWrapper) => - _activateTabWithSaveId(tabWrapper, saveId)); -} - -function _activateTabWithSaveId(tabWrapper, saveId) { - const tabsNav = tabWrapper.querySelector(':scope > .nav-tabs'); - const tabToActivate = tabsNav.querySelector(`a.nav-link[data-tab-save-id="${saveId}"]`); - if (tabToActivate) { - const tabs = tabsNav.querySelectorAll('a.nav-link'); - _clearActiveTabs(tabs); - _setActiveTab(tabToActivate); - } -} - -function _getOsForArchive() { - const os = getOS(); - // The archive doesn't have chromeos, fall back to linux. - if (os === 'chromeos') { - return 'linux'; - } - - return os; -} diff --git a/src/content/codelabs/implicit-animations.md b/src/content/codelabs/implicit-animations.md index c1338b9e135..f83f5ef66d5 100644 --- a/src/content/codelabs/implicit-animations.md +++ b/src/content/codelabs/implicit-animations.md @@ -3,9 +3,6 @@ title: "Implicit animations" description: > Learn how to use Flutter's implicitly animated widgets through interactive examples and exercises. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -13,7 +10,7 @@ js: Welcome to the implicit animations codelab, where you learn how to use Flutter widgets that make it easy to create animations for a specific set of properties. -{% render docs/dartpad-troubleshooting.md, site: site %} +{% render "docs/dartpad-troubleshooting.md", site: site %} To get the most out of this codelab, you should have basic knowledge about: @@ -59,7 +56,7 @@ consists of a [Material App][] home screen containing: To view the example, Click **Run**: -{% render docs/implicit-animations/fade-in-starter-code.md %} +{% render "docs/implicit-animations/fade-in-starter-code.md" %} ### Animate opacity with AnimatedOpacity widget @@ -78,7 +75,7 @@ widget to add the following animation feature: #### 1. Pick a widget property to animate To create a fade-in effect, you can animate the -`opacity` property using the`AnimatedOpacity` widget. +`opacity` property using the`AnimatedOpacity` widget. Wrap the `Column` widget in an `AnimatedOpacity` widget: ```dart diff @@ -126,7 +123,7 @@ the starting value for `opacity` to zero: ```dart diff class _FadeInDemoState extends State { + double opacity = 0; -+ ++ @override Widget build(BuildContext context) { return ListView(children: [ @@ -180,7 +177,7 @@ The `AnimatedOpacity` widget manages everything in between. Here's the example with the completed changes you've made. Run this example then click **Show details** to trigger the animation. -{% render docs/implicit-animations/fade-in-complete.md %} +{% render "docs/implicit-animations/fade-in-complete.md" %} ### Putting it all together @@ -214,7 +211,7 @@ It starts with a [Material App][] home screen that contains: - A `Container` widget configured with a `borderRadius`, `margin`, and `color`. - These properties are setup to be regenerated + These properties are setup to be regenerated each time you run the example. - A **Change** button that does nothing when clicked. @@ -222,7 +219,7 @@ It starts with a [Material App][] home screen that contains: To start the example, click **Run**. -{% render docs/implicit-animations/shape-shifting-starter-code.md %} +{% render "docs/implicit-animations/shape-shifting-starter-code.md" %} ### Animate color, borderRadius, and margin with AnimatedContainer @@ -336,7 +333,7 @@ Run the code and click **Change** to trigger the animation. Each time you click **Change**, the shape animates to its new values for `margin`, `borderRadius`, and `color`. -{% render docs/implicit-animations/shape-shifting-complete.md %} +{% render "docs/implicit-animations/shape-shifting-complete.md" %} ### Using animation curves diff --git a/src/content/community/china/index.md b/src/content/community/china/index.md index e959ff7c4e7..73514223d69 100644 --- a/src/content/community/china/index.md +++ b/src/content/community/china/index.md @@ -3,7 +3,7 @@ title: Using Flutter in China description: How to use, access, and learn about Flutter in China. --- -{% render docs/china-notice-cn.md %} +{% render "docs/china-notice-cn.md" %} To speed the download and installation of Flutter in China, consider using a [mirror site][] or _mirror_. @@ -30,9 +30,9 @@ _All examples that follow presume that you are using the CFUG mirror._ To set your machine to use a mirror site: -{% tabs "china-setup-os" %} + -{% tab "Windows" %} + These steps require using PowerShell. @@ -91,9 +91,9 @@ These steps require using PowerShell. [windows-path]: /install/add-to-path#windows -{% endtab %} + -{% tab "macOS" %} + 1. Open a new window in your terminal to prepare to run shell commands. @@ -151,9 +151,9 @@ These steps require using PowerShell. [macos-path]: /install/add-to-path#macos -{% endtab %} + -{% tab "Linux" %} + 1. Open a new window in your terminal to prepare to run shell commands. @@ -211,9 +211,9 @@ These steps require using PowerShell. [linux-path]: /install/add-to-path#linux -{% endtab %} + -{% endtabs %} + [Flutter SDK archive]: https://docs.flutter.cn/install/archive/ @@ -230,9 +230,9 @@ This should improve download speed. The following example shows how to change the URL for Flutter's download site from Google's archive to CFUG's mirror. -{% tabs "china-setup-os" %} + -{% tab "Windows" %} + To download the x64, Windows version of the Flutter SDK, you would change the original URL from: @@ -247,9 +247,9 @@ to the mirror URL: [!https://storage.flutter-io.cn!]/flutter_infra_release/releases/stable/windows/flutter_windows_3.35.5-stable.zip ``` -{% endtab %} + -{% tab "macOS" %} + To download the arm64, macOS version of the Flutter SDK, you would change the original URL from: @@ -264,9 +264,9 @@ to the mirror URL: [!https://storage.flutter-io.cn!]/flutter_infra_release/releases/stable/macos/flutter_macos_arm64_3.35.5-stable.zip ``` -{% endtab %} + -{% tab "Linux" %} + To download the Linux version of the Flutter SDK, you would change the original URL from: @@ -281,9 +281,9 @@ to the mirror URL: [!https://storage.flutter-io.cn!]/flutter_infra_release/releases/stable/linux/flutter_linux_3.35.5-stable.tar.xz ``` -{% endtab %} + -{% endtabs %} + :::note Not every mirror supports downloading artifacts using their direct URL. @@ -300,9 +300,9 @@ From To enable access to `pub.dev`: -{% tabs "china-setup-os" %} + -{% tab "Windows" %} + 1. Configure a proxy. To configure a proxy, check out the @@ -321,8 +321,8 @@ To enable access to `pub.dev`: $ Remove-Item $env:PUB_HOSTED_URL ``` -{% endtab %} -{% tab "macOS" %} + + 1. Configure a proxy. To configure a proxy, check out the @@ -341,8 +341,8 @@ To enable access to `pub.dev`: $ unset $PUB_HOSTED_URL ``` -{% endtab %} -{% tab "Linux" %} + + 1. Configure a proxy. To configure a proxy, check out the @@ -361,9 +361,9 @@ To enable access to `pub.dev`: $ unset $PUB_HOSTED_URL ``` -{% endtab %} + -{% endtabs %} + To learn more about publishing packages, check out the [Dart documentation on publishing packages][]. diff --git a/src/content/content.11tydata.js b/src/content/content.11tydata.js deleted file mode 100644 index 0ca2ce4d5a2..00000000000 --- a/src/content/content.11tydata.js +++ /dev/null @@ -1,3 +0,0 @@ -export default { - date: process.env.PRODUCTION === 'true' ? 'git Last Modified' : 'Last Modified', -}; diff --git a/src/content/contribute/docs/cli.md b/src/content/contribute/docs/cli.md index 83aabbf20ee..0767753dfe6 100644 --- a/src/content/contribute/docs/cli.md +++ b/src/content/contribute/docs/cli.md @@ -4,14 +4,17 @@ shortTitle: Tool description: >- Learn about the dash_site CLI tool that is used to develop, test, and serve the Dart and Flutter documentation sites. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning This document is a work in progress. ::: -The site's CLI tool can be accessed with the `./dash_site` script -in the root directory. +The site's CLI tool can be accessed by running +`dart run dash_site` in the repository's root directory. ## Commands diff --git a/src/content/contribute/docs/code-blocks.md b/src/content/contribute/docs/code-blocks.md index 723025472cb..834f2e53561 100644 --- a/src/content/contribute/docs/code-blocks.md +++ b/src/content/contribute/docs/code-blocks.md @@ -3,6 +3,9 @@ title: Code blocks description: >- Learn about Markdown code blocks on the Dart and Flutter documentation sites and custom functionality and configurability that they support. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning diff --git a/src/content/contribute/docs/components.md b/src/content/contribute/docs/components.md index 8aee7d47296..0c1a201fed0 100644 --- a/src/content/contribute/docs/components.md +++ b/src/content/contribute/docs/components.md @@ -3,6 +3,9 @@ title: Custom components description: >- Learn about custom components that the Dart and Flutter documentation sites support for displaying content. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning diff --git a/src/content/contribute/docs/docs.11tydata.json b/src/content/contribute/docs/docs.11tydata.json deleted file mode 100644 index 612cc87a0f7..00000000000 --- a/src/content/contribute/docs/docs.11tydata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sitemap": false, - "noindex": true, - "showBreadcrumbs": true -} diff --git a/src/content/contribute/docs/excerpts.md b/src/content/contribute/docs/excerpts.md index f88f9bad6ae..ae8258f1c4d 100644 --- a/src/content/contribute/docs/excerpts.md +++ b/src/content/contribute/docs/excerpts.md @@ -3,6 +3,9 @@ title: Code excerpts description: >- Learn about adding and using code excerpts in the Dart and Flutter documentation sites. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning diff --git a/src/content/contribute/docs/frontmatter.md b/src/content/contribute/docs/frontmatter.md index dfc109d4bc8..1cc96f49145 100644 --- a/src/content/contribute/docs/frontmatter.md +++ b/src/content/contribute/docs/frontmatter.md @@ -3,6 +3,9 @@ title: Frontmatter description: >- Learn about the YAML frontmatter each document on the Dart and Flutter documentation sites starts with. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning diff --git a/src/content/contribute/docs/index.md b/src/content/contribute/docs/index.md index eb4b458e1d0..0a3a41ca468 100644 --- a/src/content/contribute/docs/index.md +++ b/src/content/contribute/docs/index.md @@ -3,6 +3,9 @@ title: Contribute to the docs shortTitle: Docs description: >- Learn about contributing to the Dart and Flutter documentation sites. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning @@ -69,7 +72,7 @@ This document is a work in progress. The other directories hosting the site content. - `tool/` - - `flutter_site/` and `dash_site/` + - `dash_site/` The implementation directories for the `dash_site` tooling. - `dash_site` diff --git a/src/content/contribute/docs/markdown.md b/src/content/contribute/docs/markdown.md index f27d52b5a20..fa62002c26b 100644 --- a/src/content/contribute/docs/markdown.md +++ b/src/content/contribute/docs/markdown.md @@ -4,6 +4,9 @@ shortTitle: Markdown description: >- Learn about the Markdown syntaxes the Dart and Flutter documentation sites support and their guidelines for using them. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning diff --git a/src/content/contribute/docs/releases.md b/src/content/contribute/docs/releases.md index f94816f4b27..3a56d2b91ff 100644 --- a/src/content/contribute/docs/releases.md +++ b/src/content/contribute/docs/releases.md @@ -4,6 +4,9 @@ shortTitle: Releases description: >- Learn how to prepare for and handle new releases of Dart and Flutter on the documentation sites. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning diff --git a/src/content/contribute/docs/sidenav.md b/src/content/contribute/docs/sidenav.md index 7503212c3f5..7e498303360 100644 --- a/src/content/contribute/docs/sidenav.md +++ b/src/content/contribute/docs/sidenav.md @@ -3,6 +3,9 @@ title: Sidenav description: >- Learn about adding to and configuring the sidenav of the Dart and Flutter documentation site. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning diff --git a/src/content/contribute/docs/writing.md b/src/content/contribute/docs/writing.md index 98cb40dfe5a..5690a275ca5 100644 --- a/src/content/contribute/docs/writing.md +++ b/src/content/contribute/docs/writing.md @@ -4,6 +4,9 @@ short-tile: Writing description: >- Learn about the writing style guide and processes followed when writing for the Dart and Flutter documentation sites. +sitemap: false +noindex: true +showBreadcrumbs: true --- :::warning diff --git a/src/content/cookbook/animation/animated-container.md b/src/content/cookbook/animation/animated-container.md index 40a6946406f..885943b7e59 100644 --- a/src/content/cookbook/animation/animated-container.md +++ b/src/content/cookbook/animation/animated-container.md @@ -1,9 +1,6 @@ --- title: Animate the properties of a container description: How to animate properties of a container using implicit animations. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/animation/index.md b/src/content/cookbook/animation/index.md index 6ae387e93ad..8b3705b5200 100644 --- a/src/content/cookbook/animation/index.md +++ b/src/content/cookbook/animation/index.md @@ -1,6 +1,6 @@ --- -title: Animation +title: Flutter animation cookbook +shortTitle: Animation description: A catalog of recipes for adding animations to your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/animation/opacity-animation.md b/src/content/cookbook/animation/opacity-animation.md index e4bf9af1133..55087cb42fb 100644 --- a/src/content/cookbook/animation/opacity-animation.md +++ b/src/content/cookbook/animation/opacity-animation.md @@ -1,9 +1,6 @@ --- title: Fade a widget in and out description: How to fade a widget in and out. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/animation/page-route-animation.md b/src/content/cookbook/animation/page-route-animation.md index 0f91c035e19..3b4306152d3 100644 --- a/src/content/cookbook/animation/page-route-animation.md +++ b/src/content/cookbook/animation/page-route-animation.md @@ -1,9 +1,6 @@ --- title: Animate a page route transition description: How to animate from one page to another. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/animation/physics-simulation.md b/src/content/cookbook/animation/physics-simulation.md index a3207467484..7b4dee6fd3a 100644 --- a/src/content/cookbook/animation/physics-simulation.md +++ b/src/content/cookbook/animation/physics-simulation.md @@ -1,9 +1,6 @@ --- title: Animate a widget using a physics simulation description: How to implement a physics animation. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/design/drawer.md b/src/content/cookbook/design/drawer.md index fa3d6a82f86..aa04f2d8b37 100644 --- a/src/content/cookbook/design/drawer.md +++ b/src/content/cookbook/design/drawer.md @@ -1,9 +1,6 @@ --- title: Add a drawer to a screen description: How to implement a Material Drawer. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/design/fonts.md b/src/content/cookbook/design/fonts.md index d98e702d742..bb7d4da4ff4 100644 --- a/src/content/cookbook/design/fonts.md +++ b/src/content/cookbook/design/fonts.md @@ -94,7 +94,7 @@ Choose the typeface or font family that meets the design needs of your app. To learn how to get direct access to over 1,000 open-sourced font families, check out the [google_fonts][] package. -{% ytEmbed '8Vzv2CdbEY0', 'google_fonts | Flutter package of the week' %} + To learn about another approach to using custom fonts that allows you to re-use one font over multiple projects, diff --git a/src/content/cookbook/design/index.md b/src/content/cookbook/design/index.md index 608c2e25956..5211f3350e9 100644 --- a/src/content/cookbook/design/index.md +++ b/src/content/cookbook/design/index.md @@ -1,6 +1,6 @@ --- -title: Design +title: Flutter design cookbook +shortTitle: Design description: A catalog of recipes for designing your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/design/orientation.md b/src/content/cookbook/design/orientation.md index 428cd08ca1d..ce4f5c28345 100644 --- a/src/content/cookbook/design/orientation.md +++ b/src/content/cookbook/design/orientation.md @@ -1,9 +1,6 @@ --- title: Update the UI based on orientation description: Respond to a change in the screen's orientation. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/design/snackbars.md b/src/content/cookbook/design/snackbars.md index 589d25a0c47..685e2a075ab 100644 --- a/src/content/cookbook/design/snackbars.md +++ b/src/content/cookbook/design/snackbars.md @@ -1,9 +1,6 @@ --- title: Display a snackbar description: How to implement a snackbar to display messages. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -61,7 +58,7 @@ ScaffoldMessenger.of(context).showSnackBar(snackBar); To learn more, watch this short Widget of the Week video on the `ScaffoldMessenger` widget: -{% ytEmbed 'lytQi-slT5Y', 'ScaffoldMessenger | Flutter widget of the week' %} + ::: ## 3. Provide an optional action diff --git a/src/content/cookbook/design/tabs.md b/src/content/cookbook/design/tabs.md index f7fe3b9d1aa..095ef836a6e 100644 --- a/src/content/cookbook/design/tabs.md +++ b/src/content/cookbook/design/tabs.md @@ -1,9 +1,6 @@ --- title: Work with tabs description: How to implement tabs in a layout. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/design/themes.md b/src/content/cookbook/design/themes.md index d87d93dfa87..bfa1e79701a 100644 --- a/src/content/cookbook/design/themes.md +++ b/src/content/cookbook/design/themes.md @@ -2,9 +2,6 @@ title: Use themes to share colors and font styles shortTitle: Themes description: How to share colors and font styles throughout an app using Themes. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -164,7 +161,7 @@ Theme( To learn more, watch this short Widget of the Week video on the `Theme` widget: -{% ytEmbed 'oTvQDJOBXmM', 'Theme | Flutter widget of the week' %} + ## Try an interactive example diff --git a/src/content/cookbook/effects/download-button.md b/src/content/cookbook/effects/download-button.md index f94e50c30ba..12d406528b0 100644 --- a/src/content/cookbook/effects/download-button.md +++ b/src/content/cookbook/effects/download-button.md @@ -1,9 +1,6 @@ --- title: Create a download button description: How to implement a download button. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/effects/drag-a-widget.md b/src/content/cookbook/effects/drag-a-widget.md index 38794ceef54..0a285268688 100644 --- a/src/content/cookbook/effects/drag-a-widget.md +++ b/src/content/cookbook/effects/drag-a-widget.md @@ -1,9 +1,6 @@ --- title: Drag a UI element description: How to implement a draggable UI element. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/effects/expandable-fab.md b/src/content/cookbook/effects/expandable-fab.md index 5e98d565530..056a4e03e23 100644 --- a/src/content/cookbook/effects/expandable-fab.md +++ b/src/content/cookbook/effects/expandable-fab.md @@ -1,9 +1,6 @@ --- title: Create an expandable FAB description: How to implement a FAB that expands to multiple buttons when tapped. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/effects/index.md b/src/content/cookbook/effects/index.md index f91b0fdc530..bc95dcc6e4c 100644 --- a/src/content/cookbook/effects/index.md +++ b/src/content/cookbook/effects/index.md @@ -1,6 +1,6 @@ --- -title: Effects +title: Flutter effects cookbook +shortTitle: Effects description: A catalog of recipes for adding effects to your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/effects/nested-nav.md b/src/content/cookbook/effects/nested-nav.md index f1ae4abb495..d9599c09239 100644 --- a/src/content/cookbook/effects/nested-nav.md +++ b/src/content/cookbook/effects/nested-nav.md @@ -1,9 +1,6 @@ --- title: Create a nested navigation flow description: How to implement a flow with nested navigation. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/effects/parallax-scrolling.md b/src/content/cookbook/effects/parallax-scrolling.md index 4049a3aaf70..8a17ccda1cc 100644 --- a/src/content/cookbook/effects/parallax-scrolling.md +++ b/src/content/cookbook/effects/parallax-scrolling.md @@ -1,9 +1,6 @@ --- title: Create a scrolling parallax effect description: How to implement a scrolling parallax effect. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -205,7 +202,7 @@ to reposition your child widgets however you want. To learn more, check out this short Widget of the Week video on the `Flow` widget: -{% ytEmbed 'NG6pvXpnIso', 'Flow | Flutter widget of the week' %} + ::: :::note diff --git a/src/content/cookbook/effects/shimmer-loading.md b/src/content/cookbook/effects/shimmer-loading.md index b36f18bb172..437aa4beb62 100644 --- a/src/content/cookbook/effects/shimmer-loading.md +++ b/src/content/cookbook/effects/shimmer-loading.md @@ -1,9 +1,6 @@ --- title: Create a shimmer loading effect description: How to implement a shimmer loading effect. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/effects/staggered-menu-animation.md b/src/content/cookbook/effects/staggered-menu-animation.md index c3c04461045..53811dd236d 100644 --- a/src/content/cookbook/effects/staggered-menu-animation.md +++ b/src/content/cookbook/effects/staggered-menu-animation.md @@ -1,9 +1,6 @@ --- title: Create a staggered menu animation description: How to implement a staggered menu animation. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/effects/typing-indicator.md b/src/content/cookbook/effects/typing-indicator.md index 8ba4d4d3b3a..99c5172c23a 100644 --- a/src/content/cookbook/effects/typing-indicator.md +++ b/src/content/cookbook/effects/typing-indicator.md @@ -1,14 +1,11 @@ --- title: Create a typing indicator description: How to implement a typing indicator. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- -{% render docs/deprecated.md %} +{% render "docs/deprecated.md" %} Modern chat apps display indicators when other users are actively typing responses. These indicators help @@ -25,7 +22,7 @@ The following animation shows the app's behavior: The typing indicator exists within its own widget so that it can be used anywhere in your app. As with any widget that controls animations, the typing indicator needs to -be a stateful widget. The widget accepts a boolean value +be a stateful widget. The widget accepts a boolean value that determines whether the indicator is visible. This speech-bubble-typing indicator accepts a color for the bubbles and two colors for the light and dark @@ -72,11 +69,11 @@ when it disappears. The height of the typing indicator could be the natural height of the speech bubbles within the typing indicator. However, the speech bubbles expand with an elastic curve. -This elasticity would be too visually jarring if it quickly +This elasticity would be too visually jarring if it quickly pushed all the conversation messages up or down. Instead, the height of the typing indicator animates on its own, smoothly expanding before the bubbles appear. -When the bubbles disappear, the height smoothly contracts to zero. +When the bubbles disappear, the height smoothly contracts to zero. This behavior requires an [explicit animation][] for the height of the typing indicator. @@ -157,12 +154,12 @@ is `true` or `false`, respectively. The animation that controls the height uses different animation curves depending on its direction. -When the animation moves forward, it needs to quickly make +When the animation moves forward, it needs to quickly make space for the speech bubbles. For this reason, the forward curve runs the entire height animation within the first 40% of the overall appearance animation. When the animation reverses, it needs to give the speech bubbles -enough time to disappear before contracting the height. +enough time to disappear before contracting the height. An ease-out curve that uses all the available time is a good way to accomplish this behavior. @@ -170,11 +167,11 @@ good way to accomplish this behavior. The `AnimatedBuilder` widget rebuilds the `SizedBox` widget as the `_indicatorSpaceAnimation` changes. The alternative to using `AnimatedBuilder` is to -invoke `setState()` every time the animation changes, -and then rebuild the entire widget tree within `TypingIndicator`. +invoke `setState()` every time the animation changes, +and then rebuild the entire widget tree within `TypingIndicator`. Invoking `setState()` in this manner is acceptable, but as other widgets are added to this widget tree, -rebuilding the entire tree just to change the height +rebuilding the entire tree just to change the height of the `SizedBox` widget wastes CPU cycles. ::: @@ -182,7 +179,7 @@ of the `SizedBox` widget wastes CPU cycles. The typing indicator displays three speech bubbles. The first two bubbles are small and round. The third -bubble is oblong and contains a few flashing circles. +bubble is oblong and contains a few flashing circles. These bubbles are staggered in position from the lower left of the available space. @@ -408,7 +405,7 @@ class StatusBubble extends StatelessWidget { Within the large speech bubble, the typing indicator displays three small circles that flash repeatedly. Each circle flashes at a slightly different time, -giving the impression that a single light source is +giving the impression that a single light source is moving behind each circle. This flashing animation repeats indefinitely. diff --git a/src/content/cookbook/forms/focus.md b/src/content/cookbook/forms/focus.md index d9fd2c331bb..6ae62f4fb38 100644 --- a/src/content/cookbook/forms/focus.md +++ b/src/content/cookbook/forms/focus.md @@ -1,9 +1,6 @@ --- title: Focus and text fields description: How focus works with text fields. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/forms/index.md b/src/content/cookbook/forms/index.md index ff77d50e547..24a839518c5 100644 --- a/src/content/cookbook/forms/index.md +++ b/src/content/cookbook/forms/index.md @@ -1,6 +1,6 @@ --- -title: Forms +title: Flutter forms cookbook +shortTitle: Forms description: A catalog of Flutter form recipes. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/forms/retrieve-input.md b/src/content/cookbook/forms/retrieve-input.md index 25b685f75da..8316a35267f 100644 --- a/src/content/cookbook/forms/retrieve-input.md +++ b/src/content/cookbook/forms/retrieve-input.md @@ -1,9 +1,6 @@ --- title: Retrieve the value of a text field description: How to retrieve text from a text field. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/forms/text-field-changes.md b/src/content/cookbook/forms/text-field-changes.md index 166bf0fe826..7a0abdf2fbf 100644 --- a/src/content/cookbook/forms/text-field-changes.md +++ b/src/content/cookbook/forms/text-field-changes.md @@ -1,9 +1,6 @@ --- title: Handle changes to a text field description: How to detect changes to a text field. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/forms/text-input.md b/src/content/cookbook/forms/text-input.md index fe6516bfbff..77056ee514a 100644 --- a/src/content/cookbook/forms/text-input.md +++ b/src/content/cookbook/forms/text-input.md @@ -1,9 +1,6 @@ --- title: Create and style a text field description: How to implement a text field. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/forms/validation.md b/src/content/cookbook/forms/validation.md index 44dd8dc3ff3..78c2c87b441 100644 --- a/src/content/cookbook/forms/validation.md +++ b/src/content/cookbook/forms/validation.md @@ -1,9 +1,6 @@ --- title: Build a form with validation description: How to build a form that validates input. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/games/firestore-multiplayer.md b/src/content/cookbook/games/firestore-multiplayer.md index 0d34fee596a..db511bd9cf0 100644 --- a/src/content/cookbook/games/firestore-multiplayer.md +++ b/src/content/cookbook/games/firestore-multiplayer.md @@ -95,7 +95,7 @@ so every player sees the same state. If you want a quick, 15-minute primer on Cloud Firestore, check out the following video: -{% ytEmbed 'v_hR4K4auoQ', 'What is a NoSQL Database? Learn about Cloud Firestore' %} + To add Firestore to your Flutter project, follow the first two steps of the diff --git a/src/content/cookbook/games/index.md b/src/content/cookbook/games/index.md index 909aee9ee81..397009074f7 100644 --- a/src/content/cookbook/games/index.md +++ b/src/content/cookbook/games/index.md @@ -1,7 +1,6 @@ --- -title: Games +title: Flutter games cookbook +shortTitle: Games description: A catalog of recipes to help you build games with Flutter. +layout: toc --- - -{% include docs/cookbook-group-index.md -%} -- [Add ads to your mobile Flutter app or game](/cookbook/plugins/google-mobile-ads) diff --git a/src/content/cookbook/gestures/dismissible.md b/src/content/cookbook/gestures/dismissible.md index 3ef0b7f88b4..dba7034d15b 100644 --- a/src/content/cookbook/gestures/dismissible.md +++ b/src/content/cookbook/gestures/dismissible.md @@ -1,9 +1,6 @@ --- title: Implement swipe to dismiss description: How to implement swiping to dismiss or delete. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/gestures/handling-taps.md b/src/content/cookbook/gestures/handling-taps.md index 4ce56c9d4e8..1ad9f6d45ca 100644 --- a/src/content/cookbook/gestures/handling-taps.md +++ b/src/content/cookbook/gestures/handling-taps.md @@ -1,9 +1,6 @@ --- title: Handle taps description: How to handle tapping and dragging. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -17,7 +14,7 @@ to fundamental actions, such as tapping and dragging. To learn more, watch this short Widget of the Week video on the `GestureDetector` widget: -{% ytEmbed 'WhVXkCFPmK4', 'GestureDetector | Flutter widget of the week' %} + ::: This recipe shows how to make a custom button that shows diff --git a/src/content/cookbook/gestures/index.md b/src/content/cookbook/gestures/index.md index 8b0251ae2bd..72f8cf73091 100644 --- a/src/content/cookbook/gestures/index.md +++ b/src/content/cookbook/gestures/index.md @@ -1,6 +1,6 @@ --- -title: Gestures +title: Flutter gestures cookbook +shortTitle: Gestures description: A catalog of Flutter recipes for supporting gestures. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/gestures/ripples.md b/src/content/cookbook/gestures/ripples.md index f9a4bd063d4..092ff89179f 100644 --- a/src/content/cookbook/gestures/ripples.md +++ b/src/content/cookbook/gestures/ripples.md @@ -1,9 +1,6 @@ --- title: Add Material touch ripples description: How to implement ripple animations. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/images/index.md b/src/content/cookbook/images/index.md index 5fc006e6207..66e43360eea 100644 --- a/src/content/cookbook/images/index.md +++ b/src/content/cookbook/images/index.md @@ -1,6 +1,6 @@ --- -title: Images +title: Flutter images cookbook +shortTitle: Images description: A catalog of recipes for handling images in your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/images/network-image.md b/src/content/cookbook/images/network-image.md index f4343250436..b3651fea007 100644 --- a/src/content/cookbook/images/network-image.md +++ b/src/content/cookbook/images/network-image.md @@ -1,9 +1,6 @@ --- title: Display images from the internet description: How to display images from the internet. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/lists/basic-list.md b/src/content/cookbook/lists/basic-list.md index a2f1d8a539f..5c2877cbbbf 100644 --- a/src/content/cookbook/lists/basic-list.md +++ b/src/content/cookbook/lists/basic-list.md @@ -1,9 +1,6 @@ --- title: Use lists description: How to implement a list. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/lists/floating-app-bar.md b/src/content/cookbook/lists/floating-app-bar.md index e7067ab7e5b..2894f7d8111 100644 --- a/src/content/cookbook/lists/floating-app-bar.md +++ b/src/content/cookbook/lists/floating-app-bar.md @@ -1,9 +1,6 @@ --- title: Place a floating app bar above a list description: How to place a floating app bar or navigation bar above a list. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -51,9 +48,9 @@ For this example, create a `CustomScrollView` that contains a `SliverList`. Also, remove the app bar property from your code if it exists. -{% tabs "device-type-tabs" %} + -{% tab "Material widgets" %} + ```dart @@ -69,9 +66,9 @@ MaterialApp( ); ``` -{% endtab %} + -{% tab "Cupertino widgets" %} + ```dart @@ -87,18 +84,18 @@ CupertinoApp( ); ``` -{% endtab %} + -{% endtabs %} + ## 2. Add a floating app bar Next, add an app bar to the [`CustomScrollView`][]. -{% tabs "device-type-tabs" %} + -{% tab "Material widgets" %} + Flutter provides the [`SliverAppBar`][] widget which, much like the normal `AppBar` widget, @@ -141,19 +138,19 @@ and use hot reload to see the results. For example, use an background image that shrinks in size as it's scrolled offscreen. ::: -{% endtab %} + -{% tab "Cupertino widgets" %} + Flutter provides the [`CupertinoSliverNavigationBar`][] widget, which lets you have a "floating" navigation bar that shrinks when you scroll down and floats when you're not at the top of the page. -To create this effect: +To create this effect: 1. Add `CupertinoSliverNavigationBar` to - `CustomScrollView`. + `CustomScrollView`. 2. Start with an app bar that displays only a title. @@ -167,9 +164,9 @@ slivers: [ ], ``` -{% endtab %} + -{% endtabs %} + ## 3. Add a list of items @@ -181,9 +178,9 @@ display a list of items one after the other, use the `SliverList` widget. If you need to display a grid list, use the `SliverGrid` widget. -{% tabs "device-type-tabs" %} + -{% tab "Material widgets" %} + ```dart @@ -198,9 +195,9 @@ SliverList.builder( ) ``` -{% endtab %} + -{% tab "Cupertino widgets" %} + ```dart @@ -215,15 +212,15 @@ SliverList.builder( ) ``` -{% endtab %} + -{% endtabs %} + ## Interactive example -{% tabs "device-type-tabs" %} + -{% tab "Material widgets" %} + ```dartpad title="Flutter floating app bar hands-on example in DartPad" run="false" @@ -274,12 +271,12 @@ class MyApp extends StatelessWidget { ``` -{% endtab %} + -{% tab "Cupertino widgets" %} + ```dartpad title="Flutter floating navigation bar hands-on example in DartPad" run="false" @@ -324,12 +321,12 @@ class MyApp extends StatelessWidget { ``` -{% endtab %} + -{% endtabs %} + [`CupertinoSliverNavigationBar`]: {{site.api}}/flutter/cupertino/CupertinoSliverNavigationBar-class.html [`CustomScrollView`]: {{site.api}}/flutter/widgets/CustomScrollView-class.html diff --git a/src/content/cookbook/lists/grid-lists.md b/src/content/cookbook/lists/grid-lists.md index 2099ad136de..d8cf8acf3df 100644 --- a/src/content/cookbook/lists/grid-lists.md +++ b/src/content/cookbook/lists/grid-lists.md @@ -1,9 +1,6 @@ --- title: Create a grid list description: How to implement a grid list. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/lists/horizontal-list.md b/src/content/cookbook/lists/horizontal-list.md index 9ff25f505be..090c6f6640a 100644 --- a/src/content/cookbook/lists/horizontal-list.md +++ b/src/content/cookbook/lists/horizontal-list.md @@ -1,9 +1,6 @@ --- title: Create a horizontal list description: How to implement a horizontal list. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/lists/index.md b/src/content/cookbook/lists/index.md index 41f27cc16b5..58790640187 100644 --- a/src/content/cookbook/lists/index.md +++ b/src/content/cookbook/lists/index.md @@ -1,6 +1,6 @@ --- -title: Lists +title: Flutter lists cookbook +shortTitle: Lists description: A catalog of recipes for handling lists in your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/lists/long-lists.md b/src/content/cookbook/lists/long-lists.md index 8adebd36b4a..116e00ec3d2 100644 --- a/src/content/cookbook/lists/long-lists.md +++ b/src/content/cookbook/lists/long-lists.md @@ -1,9 +1,6 @@ --- title: Work with long lists description: Use ListView.builder to implement a long or infinite list. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/lists/mixed-list.md b/src/content/cookbook/lists/mixed-list.md index 08fea646c51..c3247031c7d 100644 --- a/src/content/cookbook/lists/mixed-list.md +++ b/src/content/cookbook/lists/mixed-list.md @@ -1,9 +1,6 @@ --- title: Create lists with different types of items description: How to implement a list that contains different types of assets. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/lists/spaced-items.md b/src/content/cookbook/lists/spaced-items.md index b483936291a..a7f27c06095 100644 --- a/src/content/cookbook/lists/spaced-items.md +++ b/src/content/cookbook/lists/spaced-items.md @@ -1,9 +1,6 @@ --- title: List with spaced items description: How to create a list with spaced or expanded items -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/maintenance/index.md b/src/content/cookbook/maintenance/index.md index beb8988d87b..484ffc81e82 100644 --- a/src/content/cookbook/maintenance/index.md +++ b/src/content/cookbook/maintenance/index.md @@ -1,6 +1,6 @@ --- -title: Maintenance +title: Flutter maintenance cookbook +shortTitle: Maintenance description: A catalog of recipes covering maintenance of Flutter apps. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/navigation/hero-animations.md b/src/content/cookbook/navigation/hero-animations.md index 03c754e6ce1..1837074e5ec 100644 --- a/src/content/cookbook/navigation/hero-animations.md +++ b/src/content/cookbook/navigation/hero-animations.md @@ -1,9 +1,6 @@ --- title: Animate a widget across screens description: How to animate a widget from one screen to another -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/navigation/index.md b/src/content/cookbook/navigation/index.md index 07a8717709e..c09d4de7e2a 100644 --- a/src/content/cookbook/navigation/index.md +++ b/src/content/cookbook/navigation/index.md @@ -1,6 +1,6 @@ --- -title: Navigation +title: Flutter navigation cookbook +shortTitle: Navigation description: A catalog of recipes for handling navigation in your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/navigation/named-routes.md b/src/content/cookbook/navigation/named-routes.md index 6f96251bf81..f5db4568d61 100644 --- a/src/content/cookbook/navigation/named-routes.md +++ b/src/content/cookbook/navigation/named-routes.md @@ -1,9 +1,6 @@ --- title: Navigate with named routes description: How to implement named routes for navigating between screens. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/navigation/navigate-with-arguments.md b/src/content/cookbook/navigation/navigate-with-arguments.md index 6bb60ab6104..ef0628a3a79 100644 --- a/src/content/cookbook/navigation/navigate-with-arguments.md +++ b/src/content/cookbook/navigation/navigate-with-arguments.md @@ -1,9 +1,6 @@ --- title: Pass arguments to a named route description: How to pass arguments to a named route. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/navigation/navigation-basics.md b/src/content/cookbook/navigation/navigation-basics.md index 01e93e68e13..5f19848aa4c 100644 --- a/src/content/cookbook/navigation/navigation-basics.md +++ b/src/content/cookbook/navigation/navigation-basics.md @@ -1,9 +1,6 @@ --- title: Navigate to a new screen and back description: How to navigate between routes. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -41,9 +38,9 @@ second route returns to the first route. First, set up the visual structure: -{% tabs "os-android" %} + -{% tab "Android" %} + ```dart @@ -86,9 +83,9 @@ class SecondRoute extends StatelessWidget { } ``` -{% endtab %} + -{% tab "iOS" %} + ```dart @@ -131,9 +128,9 @@ class SecondRoute extends StatelessWidget { } ``` -{% endtab %} + -{% endtabs %} + ## 2. Navigate to the second route using Navigator.push() @@ -148,9 +145,9 @@ to the new route using a platform-specific animation. In the `build()` method of the `FirstRoute` widget, update the `onPressed()` callback: -{% tabs "os-android" %} + -{% tab "Android" %} + ```dart @@ -165,9 +162,9 @@ onPressed: () { } ``` -{% endtab %} + -{% tab "iOS" %} + ```dart @@ -182,9 +179,9 @@ onPressed: () { } ``` -{% endtab %} + -{% endtabs %} + ## 3. Return to the first route using Navigator.pop() @@ -206,9 +203,9 @@ onPressed: () { ## Interactive example -{% tabs "os-android" %} + -{% tab "Android" %} + ```dartpad title="Flutter navigation hands-on example in DartPad" run="true" @@ -266,9 +263,9 @@ class SecondRoute extends StatelessWidget { Navigation Basics Demo -{% endtab %} + -{% tab "iOS" %} + ```dartpad title="Flutter Cupertino theme hands-on example in DartPad" run="true" @@ -326,9 +323,9 @@ class SecondRoute extends StatelessWidget { Navigation Basics Cupertino Demo -{% endtab %} + -{% endtabs %} + ## Additional navigation methods @@ -366,7 +363,7 @@ you can use. Here are a few of them: [`popUntil`]: {{site.api}}/flutter/widgets/Navigator/popUntil.html [`push`]: {{site.api}}/flutter/widgets/Navigator/push.html [`pushAndRemoveUntil`]: {{site.api}}/flutter/widgets/Navigator/pushAndRemoveUntil.html -[`pushReplacement`]: {{site.api}}/flutter/widgets/Navigator/pushReplacement.html +[`pushReplacement`]: {{site.api}}/flutter/widgets/Navigator/pushReplacement.html [`removeRoute`]: {{site.api}}/flutter/widgets/Navigator/removeRoute.html [`removeRouteBelow`]: {{site.api}}/flutter/widgets/Navigator/removeRouteBelow.html [`replace`]: {{site.api}}/flutter/widgets/Navigator/replace.html diff --git a/src/content/cookbook/navigation/passing-data.md b/src/content/cookbook/navigation/passing-data.md index 3126e30d3ef..50322e1eaa8 100644 --- a/src/content/cookbook/navigation/passing-data.md +++ b/src/content/cookbook/navigation/passing-data.md @@ -1,9 +1,6 @@ --- title: Send data to a new screen description: How to pass data to a new route. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/navigation/returning-data.md b/src/content/cookbook/navigation/returning-data.md index ade34a13373..3f49468a9df 100644 --- a/src/content/cookbook/navigation/returning-data.md +++ b/src/content/cookbook/navigation/returning-data.md @@ -1,9 +1,6 @@ --- title: Return data from a screen description: How to return data from a new screen. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/navigation/set-up-universal-links.md b/src/content/cookbook/navigation/set-up-universal-links.md index 91dc079469c..c7420084953 100644 --- a/src/content/cookbook/navigation/set-up-universal-links.md +++ b/src/content/cookbook/navigation/set-up-universal-links.md @@ -45,9 +45,9 @@ It provides a simple API to handle complex routing scenarios. ```dart title="main.dart" import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; - + void main() => runApp(MaterialApp.router(routerConfig: router)); - + /// This handles '/' and '/details'. final router = GoRouter( routes: [ @@ -83,7 +83,7 @@ It provides a simple API to handle complex routing scenarios. ::: :::note - If you're using third-party plugins to handle deep links, + If you're using third-party plugins to handle deep links, such as [app_links][], Flutter's default deeplink handler will break these plugins. @@ -99,8 +99,8 @@ Personal development teams don't support the Associated Domains capability. To add associated domains, choose the IDE tab. ::: -{% tabs %} -{% tab "Xcode" %} + + 1. Launch Xcode if necessary. @@ -129,8 +129,8 @@ capability. To add associated domains, choose the IDE tab. alt="Xcode add associated domains screenshot" width="100%" /> -{% endtab %} -{% tab "Other editors" %} + + 1. Open the `ios/Runner/Runner.entitlements` XML file in your preferred editor. @@ -169,8 +169,8 @@ perform the following steps: alt="Xcode add associated domains screenshot" width="100%" /> -{% endtab %} -{% endtabs %} + + You have finished configuring the application for deep linking. @@ -270,7 +270,7 @@ To bypass Apple's CDN, check out the [alternate mode section][]. width="50%" /> When complete, - the Flutter app displays on the home screen of the + the Flutter app displays on the home screen of the iOS device or Simulator. 1. If you test using the Simulator, use the Xcode CLI: @@ -286,7 +286,7 @@ To bypass Apple's CDN, check out the [alternate mode section][]. 1. Click the resulting link. If successful, the Flutter app launches and displays its details screen. - + Deeplinked Simulator screenshot ::: ## 1. Add the dependency diff --git a/src/content/cookbook/persistence/reading-writing-files.md b/src/content/cookbook/persistence/reading-writing-files.md index 0ef315aabd1..f0ce9b9ea90 100644 --- a/src/content/cookbook/persistence/reading-writing-files.md +++ b/src/content/cookbook/persistence/reading-writing-files.md @@ -22,7 +22,7 @@ This recipe uses the following steps: To learn more, watch this Package of the Week video on the `path_provider` package: -{% ytEmbed 'Ci4t-NkOY3I', 'path_provider | Flutter package of the week' %} + :::note This recipe doesn't work with web apps at this time. diff --git a/src/content/cookbook/plugins/index.md b/src/content/cookbook/plugins/index.md index 2f0917be279..06e0aad21b8 100644 --- a/src/content/cookbook/plugins/index.md +++ b/src/content/cookbook/plugins/index.md @@ -1,6 +1,6 @@ --- -title: Plugins +title: Flutter plugin cookbook +shortTitle: Plugins description: A catalog of recipes showcasing using plugins in your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/plugins/play-video.md b/src/content/cookbook/plugins/play-video.md index 75c59b29b25..cc6d6f3792e 100644 --- a/src/content/cookbook/plugins/play-video.md +++ b/src/content/cookbook/plugins/play-video.md @@ -1,9 +1,6 @@ --- title: Play and pause a video description: How to use the video_player plugin. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/cookbook/testing/index.md b/src/content/cookbook/testing/index.md index a8823b390ae..a1395d88ae1 100644 --- a/src/content/cookbook/testing/index.md +++ b/src/content/cookbook/testing/index.md @@ -1,16 +1,5 @@ --- title: Testing description: A catalog of recipes showcasing testing your Flutter app. +layout: toc --- - -## Integration - -{% include docs/testing-toc.md type='integration' %} - -## Unit - -{% include docs/testing-toc.md type='unit' %} - -## Widget - -{% include docs/testing-toc.md type='widget' %} \ No newline at end of file diff --git a/src/content/cookbook/testing/integration/index.md b/src/content/cookbook/testing/integration/index.md index 1bc7abf829b..116e51b1d1d 100644 --- a/src/content/cookbook/testing/integration/index.md +++ b/src/content/cookbook/testing/integration/index.md @@ -1,7 +1,7 @@ --- -title: Integration +title: Integration testing +breadcrumb: Integration description: > A catalog of recipes for adding integration testing to your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/testing/integration/introduction.md b/src/content/cookbook/testing/integration/introduction.md index 33fbae65fdb..f8f02e071dd 100644 --- a/src/content/cookbook/testing/integration/introduction.md +++ b/src/content/cookbook/testing/integration/introduction.md @@ -24,8 +24,8 @@ The Flutter SDK includes the [integration_test][] package. : The system on which you develop your app, like a desktop computer. **target device** -: The mobile device, browser, or desktop application that runs -your Flutter app. +: The mobile device, browser, or desktop application that + runs your Flutter app. If you run your app in a web browser or as a desktop application, the host machine and the target device are the same. @@ -55,6 +55,5 @@ The other guides in this section explain how to use integration tests to validat [functionality]: /testing/integration-tests/ [performance]: /cookbook/testing/integration/profiling/ [integration_test]: {{site.repo.flutter}}/tree/main/packages/integration_test -[Migrating from flutter_driver]: - /release/breaking-changes/flutter-driver-migration +[Migrating from flutter_driver]: /release/breaking-changes/flutter-driver-migration [widget tests]: /testing/overview#widget-tests diff --git a/src/content/cookbook/testing/unit/index.md b/src/content/cookbook/testing/unit/index.md index 0af86d5cc47..94aed087c24 100644 --- a/src/content/cookbook/testing/unit/index.md +++ b/src/content/cookbook/testing/unit/index.md @@ -1,6 +1,6 @@ --- -title: Unit +title: Unit testing +breadcrumb: Unit description: A catalog of recipes for adding unit testing to your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/cookbook/testing/widget/index.md b/src/content/cookbook/testing/widget/index.md index cc3e379c761..08fbec48883 100644 --- a/src/content/cookbook/testing/widget/index.md +++ b/src/content/cookbook/testing/widget/index.md @@ -1,6 +1,6 @@ --- -title: Widget +title: Widget testing +breadcrumb: Widget description: A catalog of recipes for adding widget testing to your Flutter app. +layout: toc --- - -{% include docs/cookbook-group-index.md %} diff --git a/src/content/dash/index.md b/src/content/dash/index.md index c9723b0535c..a80d085d778 100644 --- a/src/content/dash/index.md +++ b/src/content/dash/index.md @@ -84,7 +84,7 @@ manufacturers who returned the prototypes some weeks later. ![The first Dash prototypes](/assets/images/dash/dash-prototypes.jpg){:width="35%"} ![The first Dash prototypes](/assets/images/dash/dash-prototypes2.jpg){:width="35%"}
-{% ytEmbed 'R5vIUjRZaZA', 'Introducing Dash at the January 2018 Dart Conference' %} + While the manufacturing process was proceeding, Shams chose a name for the plushy: Dash, @@ -133,7 +133,7 @@ Dash 2.0 and 2.1 first appearance at the [Flutter Interact][] event in Brooklyn, New York, on December 11, 2019. - {% ytEmbed 'EgBMGDtHZhE', 'Flutter Interact 2019 highlights' %} + * We also have a Dash puppet that Shams made from one of the first plushies. @@ -144,9 +144,9 @@ Dash 2.0 and 2.1 voiced by Emily Fortuna, one of the early (and much loved) Flutter Developer Advocates. - {% ytEmbed 'oyy_1CjNdBU', 'Building DashCast, a Flutter-based podcast app' %} + - {% ytEmbed 'dsiLVNDJ3t0', 'Revisiting DashCast, a Flutter-based podcast app' %} + ![Born to Hot Reload jacket](/assets/images/dash/ShamsDashJacket.png){:width="35%"} diff --git a/src/content/data-and-backend/serialization/json.md b/src/content/data-and-backend/serialization/json.md index 34eed131b1c..ef4a4f23ee2 100644 --- a/src/content/data-and-backend/serialization/json.md +++ b/src/content/data-and-backend/serialization/json.md @@ -27,7 +27,7 @@ overall process, and "encoding" and "decoding" when specifically referring to those processes. ::: -{% ytEmbed 'ngsxzZt5DoY', 'dart:convert (Technique of the Week)' %} + ## Which JSON serialization method is right for me? diff --git a/src/content/data-and-backend/state-mgmt/options.md b/src/content/data-and-backend/state-mgmt/options.md index 6d42c61e49f..fa568ced83b 100644 --- a/src/content/data-and-backend/state-mgmt/options.md +++ b/src/content/data-and-backend/state-mgmt/options.md @@ -68,7 +68,7 @@ This is what `package:provider` and many other approaches use under the hood. The following instructor-led video workshop covers how to use `InheritedWidget`: -{% ytEmbed 'LFcGPS6cGrY', 'How to manage application state using inherited widgets' %} + Other useful docs include: diff --git a/src/content/deployment/android.md b/src/content/deployment/android.md index fd594cff3cc..257d81e439f 100644 --- a/src/content/deployment/android.md +++ b/src/content/deployment/android.md @@ -139,7 +139,7 @@ If not, create one using one of the following methods: On Windows, use the following command in PowerShell: - ```powershell + ```ps keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks ` -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 ` -alias upload diff --git a/src/content/deployment/ios.md b/src/content/deployment/ios.md index c2637f63137..157548efcfb 100644 --- a/src/content/deployment/ios.md +++ b/src/content/deployment/ios.md @@ -25,7 +25,7 @@ You can read more about the various membership options in Apple's For those who prefer video over text, the following video covers the same material as this guide. -{% ytEmbed 'iE2bpP56QKc', 'Release an iOS app built with Flutter in 7 steps' %} + ## Register your app on App Store Connect diff --git a/src/content/favicon.ico b/src/content/favicon.ico deleted file mode 100644 index 2eb40016c20..00000000000 Binary files a/src/content/favicon.ico and /dev/null differ diff --git a/src/content/get-started/codelab.md b/src/content/get-started/codelab.md index 658f845a1b2..605a8b08399 100644 --- a/src/content/get-started/codelab.md +++ b/src/content/get-started/codelab.md @@ -41,4 +41,4 @@ app for all platforms — mobile, desktop, and web. If you prefer an instructor-led version of this codelab, check out the following workshop: -{% ytEmbed '8sAyPDLorek', 'Building your first Flutter app - with a Codelab!' %} + diff --git a/src/content/get-started/custom.md b/src/content/get-started/custom.md index f8839324684..6aa3dfdc7f7 100644 --- a/src/content/get-started/custom.md +++ b/src/content/get-started/custom.md @@ -166,7 +166,7 @@ Follow the codelab on [Building your first app][], set up development for an [additional target platform][], or explore some of these other learning resources. -{% render docs/get-started/setup-next-steps.html, site:site %} +{% render "docs/get-started/setup-next-steps.html", site:site %} [Building your first app]: /get-started/codelab [additional target platform]: /platform-integration#setup diff --git a/src/content/get-started/flutter-for/react-native-devs.md b/src/content/get-started/flutter-for/react-native-devs.md index 6e1a5df1edd..a353a502172 100644 --- a/src/content/get-started/flutter-for/react-native-devs.md +++ b/src/content/get-started/flutter-for/react-native-devs.md @@ -451,7 +451,7 @@ void main() { The following images show the Android and iOS UI for the basic Flutter "Hello world!" app. -{% render docs/android-ios-figure-pair.md, image: "react-native/hello-world-basic.png", alt: "Hello world app", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/hello-world-basic.png", alt: "Hello world app", class: "border" %} Now that you've seen the most basic Flutter app, the next section shows how to take advantage of Flutter's rich widget libraries to create a modern, polished @@ -505,7 +505,7 @@ class MyApp extends StatelessWidget { The following images show "Hello world!" built from Material Design widgets. You get more functionality for free than in the basic "Hello world!" app. -{% render docs/android-ios-figure-pair.md, image: "react-native/hello-world.png", alt: "Hello world app" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/hello-world.png", alt: "Hello world app" %} When writing an app, you'll use two types of widgets: [`StatelessWidget`][] or [`StatefulWidget`][]. @@ -606,7 +606,7 @@ the constructor, or add `required` to the constructor. The following screenshots show an example of the reusable `CustomCard` class. -{% render docs/android-ios-figure-pair.md, image: "react-native/custom-cards.png", alt: "Custom cards", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/custom-cards.png", alt: "Custom cards", class: "border" %} ## Project structure and resources @@ -837,7 +837,7 @@ return ListView.builder( ); ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/flatlist.webp", alt: "Flat list", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/flatlist.webp", alt: "Flat list", class: "border" %} To learn how to implement an infinite scrolling list, see the official [`infinite_list`][infinite_list] sample. @@ -907,7 +907,7 @@ class MyCanvasWidget extends StatelessWidget { } ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/canvas.png", alt: "Canvas", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/canvas.png", alt: "Canvas", class: "border" %} ## Layouts @@ -963,7 +963,7 @@ For example, [`Padding`][], [`Align`][], and [`Stack`][]. For a complete list, see [Layout Widgets][]. -{% render docs/android-ios-figure-pair.md, image: "react-native/basic-layout.webp", alt: "Layout", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/basic-layout.webp", alt: "Layout", class: "border" %} ### How do I layer widgets? @@ -999,7 +999,7 @@ on top of a `CircleAvatar`. The Stack offsets the text using the alignment property and `Alignment` coordinates. -{% render docs/android-ios-figure-pair.md, image: "react-native/stack.png", alt: "Stack", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/stack.png", alt: "Stack", class: "border" %} For more information, see the [`Stack`][] class documentation. @@ -1058,7 +1058,7 @@ return const Center( ); ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/flutterstyling.webp", alt: "Styling", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/flutterstyling.webp", alt: "Styling", class: "border" %} ### How do I use `Icons` and `Colors`? @@ -1090,7 +1090,7 @@ flutter: Flutter's [Cupertino (iOS-style)][] package provides high fidelity widgets for the current iOS design language. To use the `CupertinoIcons` font, -add a dependency for `cupertino_icons` in your project's +add a dependency for `cupertino_icons` in your project's `pubspec.yaml` file. ```yaml @@ -1406,7 +1406,7 @@ class MyStatelessWidget extends StatelessWidget { } ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/state-change.webp", alt: "State change", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/state-change.webp", alt: "State change", class: "border" %} ## Props @@ -1489,7 +1489,7 @@ class UseCard extends StatelessWidget { } ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/modular.png", alt: "Cards", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/modular.png", alt: "Cards", class: "border" %} ## Local storage @@ -1853,7 +1853,7 @@ Widget build(BuildContext context) { } ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/navigation.webp", alt: "Navigation", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/navigation.webp", alt: "Navigation", class: "border" %} ## Gesture detection and touch event handling @@ -1959,7 +1959,7 @@ see the [GestureDetector class][]. [GestureDetector class]: {{site.api}}/flutter/widgets/GestureDetector-class.html#instance-properties -{% render docs/android-ios-figure-pair.md, image: "react-native/flutter-gestures.webp", alt: "Gestures", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/flutter-gestures.webp", alt: "Gestures", class: "border" %} ## Making HTTP network requests @@ -1987,7 +1987,7 @@ const _getIPAddress = () => { }; ``` -Flutter uses the `http` package. +Flutter uses the `http` package. To add the `http` package as a dependency, run `flutter pub add`: @@ -2022,7 +2022,7 @@ Future getIPAddress() async { } ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/api-calls.webp", alt: "API calls", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/api-calls.webp", alt: "API calls", class: "border" %} ## Form input @@ -2165,7 +2165,7 @@ void _submit() { } ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/input-fields.webp", alt: "Input", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/input-fields.webp", alt: "Input", class: "border" %} ## Platform-specific code @@ -2244,7 +2244,7 @@ enable autosave and hot reloads on save. `Configure autosave options`. - Check the option to `Save files if the IDE is idle for X seconds`. - **Recommended:** Set a small delay duration. For example, 2 seconds. - + * Open `Settings > Languages & Frameworks > Flutter`. - Check the option to `Perform hot reload on save`. @@ -2428,7 +2428,7 @@ class _LogoFadeState extends State } ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/flutter-fade.webp", alt: "Flutter fade", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/flutter-fade.webp", alt: "Flutter fade", class: "border" %} ### How do I add swipe animation to cards? @@ -2451,7 +2451,7 @@ return Dismissible( ); ``` -{% render docs/android-ios-figure-pair.md, image: "react-native/card-swipe.webp", alt: "Card swipe", class: "border" %} +{% render "docs/android-ios-figure-pair.md", image: "react-native/card-swipe.webp", alt: "Card swipe", class: "border" %} ## React Native and Flutter widget equivalent components diff --git a/src/content/get-started/flutter-for/swiftui-devs.md b/src/content/get-started/flutter-for/swiftui-devs.md index 53f5ae507d3..fc4092bf72a 100644 --- a/src/content/get-started/flutter-for/swiftui-devs.md +++ b/src/content/get-started/flutter-for/swiftui-devs.md @@ -47,7 +47,7 @@ you can open and run some of the examples on DartPad. As an introduction, watch the following video. It outlines how Flutter works on iOS and how to use Flutter to build iOS apps. -{% ytEmbed 'ceMsPBbcEGg', 'Flutter for iOS developers', true %} + Flutter and SwiftUI code describes how the UI looks and works. Developers call this type of code a _declarative framework_. @@ -157,7 +157,7 @@ your Flutter app can use many different design systems: - Your own custom widgets - [Cupertino widgets][] that follow Apple's Human Interface Guidelines -{% ytEmbed '3PdUaidHc-E', 'Flutter\'s cupertino library for iOS developers' %} + If you're looking for a great reference app that features a custom design system, check out [Wonderous][]. diff --git a/src/content/get-started/flutter-for/uikit-devs.md b/src/content/get-started/flutter-for/uikit-devs.md index 3ef00b56927..1da231fad6e 100644 --- a/src/content/get-started/flutter-for/uikit-devs.md +++ b/src/content/get-started/flutter-for/uikit-devs.md @@ -46,7 +46,7 @@ Jump around and find questions that address your most relevant needs. As an introduction, watch the following video. It outlines how Flutter works on iOS and how to use Flutter to build iOS apps. -{% ytEmbed 'ceMsPBbcEGg', 'Flutter for iOS developers', true %} + ### Views vs. Widgets diff --git a/src/content/get-started/fundamentals/index.md b/src/content/get-started/fundamentals/index.md index f5b3d2acf47..f76f1fe6b96 100644 --- a/src/content/get-started/fundamentals/index.md +++ b/src/content/get-started/fundamentals/index.md @@ -26,7 +26,7 @@ how Flutter works.
- {% render docs/app-figure.md, image:"fwe/dash-search.png", alt:"Dash with magnifying glass", img-style: "max-height: 320px;"%} +
@@ -77,7 +77,7 @@ following subjects in the listed order. functionality, such as how to retrieve or submit data using HTTP, how to convert to and from JSON, - how to use authentication, + how to use authentication, how to implement asynchronicity, and more. 7. [Local data and caching][] Learn about different techniques for caching diff --git a/src/content/get-started/fundamentals/layout.md b/src/content/get-started/fundamentals/layout.md index f2087281be6..7184ea9f187 100644 --- a/src/content/get-started/fundamentals/layout.md +++ b/src/content/get-started/fundamentals/layout.md @@ -23,25 +23,25 @@ the dreaded "unbounded constraints" error. ## Understanding layout in Flutter -The core of Flutter's layout mechanism is widgets. -In Flutter, almost everything is a widget — even -layout models are widgets. -The images, icons, and text that you see in a -Flutter app are all widgets. -Things you don't see are also widgets, +The core of Flutter's layout mechanism is widgets. +In Flutter, almost everything is a widget — even +layout models are widgets. +The images, icons, and text that you see in a +Flutter app are all widgets. +Things you don't see are also widgets, such as the rows, columns, and grids that arrange, constrain, and align the visible widgets. -You create a layout by composing widgets to -build more complex widgets. For example, +You create a layout by composing widgets to +build more complex widgets. For example, the diagram below shows 3 icons with a label under each one, and the corresponding widget tree: A diagram that shows widget composition with a series of lines and nodes. -In this example, there's a row of 3 columns where -each column contains an icon and a label. -All layouts, no matter how complex, +In this example, there's a row of 3 columns where +each column contains an icon and a label. +All layouts, no matter how complex, are created by composing these layout widgets. ### Constraints @@ -50,79 +50,79 @@ Understanding constraints in Flutter is an important part of understanding how layout works in Flutter. -Layout, in a general sense, refers to the size of -the widgets and their positions on the screen. -The size and position of any given widget is -constrained by its parent; -it can't have any size it wants, +Layout, in a general sense, refers to the size of +the widgets and their positions on the screen. +The size and position of any given widget is +constrained by its parent; +it can't have any size it wants, and it doesn't decide its own place on the screen. -Instead, size and position are determined by +Instead, size and position are determined by a conversation between a widget and its parent. -In the simplest example, +In the simplest example, the layout conversation looks like this: - 1. A widget receives its constraints from its parent. - 2. A constraint is just a set of 4 doubles: - a minimum and maximum width, - and a minimum and maximum height. + 1. A widget receives its constraints from its parent. + 2. A constraint is just a set of 4 doubles: + a minimum and maximum width, + and a minimum and maximum height. 3. The widget determines what size it should be within those constraints, and passes its - width and height back to the parent. + width and height back to the parent. 4. The parent looks at the size it wants to be and - how it should be aligned, - and sets the widget's position accordingly. - Alignment can be set explicitly, - using a variety of widgets like `Center`, + how it should be aligned, + and sets the widget's position accordingly. + Alignment can be set explicitly, + using a variety of widgets like `Center`, and the alignment properties on `Row` and `Column`. -In Flutter, this layout conversation is often -expressed with the simplified phrase, -"Constraints go down. Sizes go up. +In Flutter, this layout conversation is often +expressed with the simplified phrase, +"Constraints go down. Sizes go up. Parent sets the position." ### Box types -In Flutter, widgets are rendered by their -underlying [`RenderBox`][] objects. +In Flutter, widgets are rendered by their +underlying [`RenderBox`][] objects. These objects determine how to handle the constraints they're passed. Generally, there are three kinds of boxes: -* Those that try to be as big as possible. -For example, the boxes used by -[`Center`][] and [`ListView`][]. +* Those that try to be as big as possible. +For example, the boxes used by +[`Center`][] and [`ListView`][]. * Those that try to be the same size as their -children. For example, the boxes used by +children. For example, the boxes used by [`Transform`][] and [`Opacity`][] * Those that try to be a particular size. -For example, the boxes used by +For example, the boxes used by [`Image`][] and [`Text`][]. -Some widgets, for example [`Container`][], -vary from type to type based on their -constructor arguments. +Some widgets, for example [`Container`][], +vary from type to type based on their +constructor arguments. The `Container` constructor defaults to trying to be as big as possible, but if you give it a width, -for instance, it tries to honor that and +for instance, it tries to honor that and be that particular size. -Others, for example [`Row`][] and [`Column`][] (flex boxes) -vary based on the constraints they are given. +Others, for example [`Row`][] and [`Column`][] (flex boxes) +vary based on the constraints they are given. Read more about flex boxes and constraints in the [Understanding Constraints article][]. ## Lay out a single widget -To lay out a single widget in Flutter, -wrap a visible widget, -such as `Text` or `Image` with a widget that -can change its position on a screen, +To lay out a single widget in Flutter, +wrap a visible widget, +such as `Text` or `Image` with a widget that +can change its position on a screen, such as a `Center` widget. :::note Note -The examples on the page use a widget called -`BorderedImage`. This is a custom widget, +The examples on the page use a widget called +`BorderedImage`. This is a custom widget, and is used here to hide the code that isn't relevant to this topic. ::: @@ -135,30 +135,30 @@ Widget build(BuildContext context) { } ``` -The following figure shows a widget that isn't -aligned on the left, +The following figure shows a widget that isn't +aligned on the left, and a widget that has been centered on the right. A screenshot of a centered widget and a screenshot of a widget that hasn't been centered. All layout widgets have either of the following: -* A `child` property if they take a single +* A `child` property if they take a single child—for example, `Center`, `Container`, or `Padding`. -* A `children` property if they take a list -of widgets—for example, +* A `children` property if they take a list +of widgets—for example, `Row`, `Column`, `ListView`, or `Stack`. ### Container -`Container` is a convenience widget that's +`Container` is a convenience widget that's made up of several widgets responsible for layout, -painting, positioning, and sizing. -In regard to layout, -it can be used to add padding and -margins to a widget. +painting, positioning, and sizing. +In regard to layout, +it can be used to add padding and +margins to a widget. There is also a `Padding` widget -that could be used here to the same effect. +that could be used here to the same effect. The following example uses a `Container`. ```dart @@ -170,14 +170,14 @@ Widget build(BuildContext context) { } ``` -The following figure shows a widget without -padding on the left, +The following figure shows a widget without +padding on the left, and a widget with padding on the right. A screenshot of a widget with padding and a screenshot of a widget without padding. -To create more complex layouts in Flutter, -you can compose many widgets. +To create more complex layouts in Flutter, +you can compose many widgets. For example, you can combine `Container` and `Center`: ```dart @@ -193,16 +193,16 @@ Widget build(BuildContext context) { ## Layout multiple widgets vertically or horizontally -One of the most common layout patterns is to -arrange widgets vertically or horizontally. -You can use a `Row` widget to arrange widgets -horizontally, -and a `Column` widget to arrange widgets vertically. +One of the most common layout patterns is to +arrange widgets vertically or horizontally. +You can use a `Row` widget to arrange widgets +horizontally, +and a `Column` widget to arrange widgets vertically. The first figure on this page used both. This is the most basic example of using a `Row` widget. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/layout/row.png", caption: "This figure shows a row widget with three children." alt: "A screenshot of a row widget with three children" @@ -220,14 +220,14 @@ Widget build(BuildContext context) { ``` " %} -Each child of `Row` or `Column` can be -rows and columns themselves, +Each child of `Row` or `Column` can be +rows and columns themselves, combining to make a complex layout. -For example, you could add labels to each +For example, you could add labels to each of the images in the example above using columns. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/layout/nested_row_column.png", caption: "This figure shows a row widget with three children, each of which is a column." alt: "A screenshot of a row of three widgets, each of which has a label underneath it." @@ -263,30 +263,30 @@ Widget build(BuildContext context) { ### Align widgets within rows and columns -In the following example, -the widgets are each 200 pixels wide, -and the viewport is 700 pixels wide. -The widgets are consequently aligned to the left, -one after the other, +In the following example, +the widgets are each 200 pixels wide, +and the viewport is 700 pixels wide. +The widgets are consequently aligned to the left, +one after the other, with all the extra space on the right. A diagram that shows three widgets laid out in a row. Each child widget is labeled as 200px wide, and the blank space on the right is labeled as 100px wide. You control how a row or column aligns its -children using the `mainAxisAlignment` and +children using the `mainAxisAlignment` and `crossAxisAlignment` properties. -For a row, the main axis runs horizontally and -the cross axis runs vertically. For a column, +For a row, the main axis runs horizontally and +the cross axis runs vertically. For a column, the main axis runs vertically and the cross axis runs horizontally. A diagram that shows the direction of the main axis and cross axis in both rows and columns -Setting the main axis alignment to `spaceEvenly` +Setting the main axis alignment to `spaceEvenly` divides the free horizontal space evenly between, before, and after each image. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/layout/space_evenly.png", caption: "This figure shows a row widget with three children, which are aligned with the MainAxisAlignment.spaceEvenly constant." alt: "A screenshot of three widgets, spaced evenly from each other." @@ -305,41 +305,41 @@ Widget build(BuildContext context) { ``` " %} -Columns work the same way as rows. -The following example shows a column of 3 images, -each is 100 pixels high. The height of the -render box (in this case, the entire screen) -is more than 300 pixels, -so setting the main axis alignment to `spaceEvenly` +Columns work the same way as rows. +The following example shows a column of 3 images, +each is 100 pixels high. The height of the +render box (in this case, the entire screen) +is more than 300 pixels, +so setting the main axis alignment to `spaceEvenly` divides the free vertical space evenly between, above, and below each image. A screenshot of a three widgets laid out vertically, using a column widget. -The [`MainAxisAlignment`][] and [`CrossAxisAlignment`][] -enums offer a variety of constants for +The [`MainAxisAlignment`][] and [`CrossAxisAlignment`][] +enums offer a variety of constants for controlling alignment. -Flutter includes other widgets that can be used +Flutter includes other widgets that can be used for alignment, notably the `Align` widget. ### Sizing widgets within rows and columns -When a layout is too large to fit a device, -a yellow and black striped pattern appears -along the affected edge. +When a layout is too large to fit a device, +a yellow and black striped pattern appears +along the affected edge. In this example, the viewport is 400 pixels wide, and each child is 150 pixels wide. A screenshot of a row of widgets that are wider than their viewport. -Widgets can be sized to fit within a -row or column by using the `Expanded` widget. -To fix the previous example where the row of -images is too wide for its render box, +Widgets can be sized to fit within a +row or column by using the `Expanded` widget. +To fix the previous example where the row of +images is too wide for its render box, wrap each image with an [`Expanded`][] widget. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/layout/expanded_row.png", caption: "This figure shows a row widget with three children that are wrapped with `Expanded` widgets." alt: "A screenshot of three widgets, which take up exactly the amount of space available on the main axis. All three widgets are equal width." @@ -363,18 +363,18 @@ Widget build(BuildContext context) { ``` " %} -The `Expanded` widget can also dictate how much +The `Expanded` widget can also dictate how much space a widget should take up relative to its siblings. For example, -perhaps you want a widget to occupy twice -as much space as its siblings. -For this, use the `Expanded` widgets `flex` property, -an integer that determines the flex factor -for a widget. The default flex factor is 1. +perhaps you want a widget to occupy twice +as much space as its siblings. +For this, use the `Expanded` widgets `flex` property, +an integer that determines the flex factor +for a widget. The default flex factor is 1. The following code sets the flex factor of the middle image to 2: -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/layout/flex_2_row.png", caption: "This figure shows a row widget with three children which are wrapped with `Expanded` widgets. The center child has it's `flex` property set to 2." alt: "A screenshot of three widgets, which take up exactly the amount of space available on the main axis. The widget in the center is twice as wide as the widgets on the left and right." @@ -401,41 +401,41 @@ Widget build(BuildContext context) { ## DevTools and debugging layout -In certain situations, -a box's constraint is unbounded, or infinite. +In certain situations, +a box's constraint is unbounded, or infinite. This means that either the maximum width or the -maximum height is set to [`double.infinity`][]. +maximum height is set to [`double.infinity`][]. A box that tries to be as big as possible won't -function usefully when given an -unbounded constraint and, in debug mode, +function usefully when given an +unbounded constraint and, in debug mode, throws an exception. The most common case where a render box ends up -with an unbounded constraint is within a -flex box ([`Row`][] or [`Column`][]), -and within a scrollable region -(such as [`ListView`][] and other [`ScrollView`][] subclasses). +with an unbounded constraint is within a +flex box ([`Row`][] or [`Column`][]), +and within a scrollable region +(such as [`ListView`][] and other [`ScrollView`][] subclasses). `ListView`, for example, tries to expand to -fit the space available in its cross-direction +fit the space available in its cross-direction (perhaps it's a vertically-scrolling -block and tries to be as wide as its parent). +block and tries to be as wide as its parent). If you nest a vertically scrolling `ListView` inside a horizontally scrolling `ListView`, -the inner list tries to be as wide as possible, +the inner list tries to be as wide as possible, which is infinitely wide, since the outer one is scrollable in that direction. -Perhaps the most common error you'll run into -while building a Flutter application is due to -incorrectly using layout widgets, -and is referred to as the "unbounded constraints" +Perhaps the most common error you'll run into +while building a Flutter application is due to +incorrectly using layout widgets, +and is referred to as the "unbounded constraints" error. -If there was only one type error you should be +If there was only one type error you should be prepared to confront when you first start building Flutter apps, it would be this one. -{% ytEmbed 'jckqXR5CrPI', 'Decoding Flutter: Unbounded height and width' %} + :::note The Widget inspector Flutter has a robust suite of DevTools that @@ -459,17 +459,17 @@ as well as a widget for creating scrollable lists. ### ListView -`ListView` is a column-like widget that -automatically provides scrolling when its +`ListView` is a column-like widget that +automatically provides scrolling when its content is longer than its render box. -The most basic way to use a `ListView` is -very similar to using a `Column` or `Row`. -Unlike a column or row, -a `ListView` requires its children to take up -all the available space on the cross axis, -as shown in the example below. - -{% render docs/code-and-image.md, +The most basic way to use a `ListView` is +very similar to using a `Column` or `Row`. +Unlike a column or row, +a `ListView` requires its children to take up +all the available space on the cross axis, +as shown in the example below. + +{% render "docs/code-and-image.md", image:"fwe/layout/basic_listview.png", caption: "This figure shows a ListView widget with three children." alt: "A screenshot of three widgets laid out vertically. They have expanded to take up all available space on the cross axis." @@ -487,20 +487,20 @@ Widget build(BuildContext context) { ``` " %} -`ListView`s are commonly used when you have an -unknown or very large (or infinite) number of list items. -When this is the case, -it's best to use the `ListView.builder` constructor. -The builder constructor only builds the +`ListView`s are commonly used when you have an +unknown or very large (or infinite) number of list items. +When this is the case, +it's best to use the `ListView.builder` constructor. +The builder constructor only builds the children that are currently visible on screen. -In the following example, -the `ListView` is displaying a list of to-do items. -The todo items are being fetched from a repository, +In the following example, +the `ListView` is displaying a list of to-do items. +The todo items are being fetched from a repository, and therefore the number of todos is unknown. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/layout/listview_builder.png", caption: "This figure shows the ListView.builder constructor to display an unknown number of children." alt: "A screenshot of several widgets laid out vertically. They have expanded to take up all available space on the cross axis." @@ -539,16 +539,16 @@ things like screen size or input device. This is referred to as making an app _adaptive_ and _responsive_. -One of the most useful widgets in making -adaptive layouts is the [`LayoutBuilder`][] widget. +One of the most useful widgets in making +adaptive layouts is the [`LayoutBuilder`][] widget. `LayoutBuilder` is one of many widgets that uses the "builder" pattern in Flutter. ### The builder pattern -In Flutter, you'll find several widgets that use -the word "builder" in their names or -in their constructors. +In Flutter, you'll find several widgets that use +the word "builder" in their names or +in their constructors. The following list isn't exhaustive: * [`ListView.builder`][] @@ -557,48 +557,48 @@ The following list isn't exhaustive: * [`LayoutBuilder`][] * [`FutureBuilder`][] -These different "builders" are useful for solving -different problems. For example, +These different "builders" are useful for solving +different problems. For example, the `ListView.builder` constructor is primarily used -to lazily render items in a list, -while the `Builder` widget is useful for gaining +to lazily render items in a list, +while the `Builder` widget is useful for gaining access to the `BuildContext` in deeply widget code. -Despite their different use cases, -these builders are unified by how they work. -Builder widgets and builder constructors all have -arguments called 'builder' -(or something similar, -like `itemBuilder` in the case of `ListView.builder`), +Despite their different use cases, +these builders are unified by how they work. +Builder widgets and builder constructors all have +arguments called 'builder' +(or something similar, +like `itemBuilder` in the case of `ListView.builder`), and the builder argument always accepts a -callback. -This callback is a __builder function__. +callback. +This callback is a __builder function__. Builder functions are callbacks that pass data to -the parent widget, -and the parent widget uses those arguments to +the parent widget, +and the parent widget uses those arguments to build and return the child widget. Builder functions always pass in at least one argument–the build context– and generally at least one other argument. -For example, the `LayoutBuilder` widget is used -to create responsive layouts based +For example, the `LayoutBuilder` widget is used +to create responsive layouts based on the size of the viewport. The builder callback body is passed the [`BoxConstraints`][] that it receives -from its parent, along with the widgets 'BuildContext'. +from its parent, along with the widgets 'BuildContext'. With these constraints, you can return a different widget based on the available space. -{% ytEmbed 'IYDVcriKjsw', 'LayoutBuilder (Flutter Widget of the Week)' %} + -In the following example, -the widget returned by the `LayoutBuilder` -changes based on whether the viewport is +In the following example, +the widget returned by the `LayoutBuilder` +changes based on whether the viewport is less than or equal 600 pixels, or greater than 600 pixels. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/layout/layout_builder.png", caption: "This figure shows a narrow layout, which lays out its children vertically, and a wider layout, which lays out its children in a grid." alt: "Two screenshots, in which one shows a narrow layout and the other shows a wide layout." @@ -618,18 +618,18 @@ Widget build(BuildContext context) { ``` " %} -Meanwhile, the `itemBuilder` callback on the -`ListView.builder` constructor is passed the +Meanwhile, the `itemBuilder` callback on the +`ListView.builder` constructor is passed the build context and an `int`. -This callback is called once for every item -in the list, -and the int argument represents the index of the list item. -The first time the itemBuilder callback is called -when Flutter is building the UI, -the int passed to the function is 0, +This callback is called once for every item +in the list, +and the int argument represents the index of the list item. +The first time the itemBuilder callback is called +when Flutter is building the UI, +the int passed to the function is 0, the second time it's 1, and so on. -This allows you to provide specific configuration +This allows you to provide specific configuration based on the index. Recall the example above using the`ListView.builder` constructor: @@ -656,17 +656,17 @@ Widget build(BuildContext context) { } ``` -This example code uses the index that's -passed into the builder to grab the correct -todo from the list of items, -and then displays that todo's data in +This example code uses the index that's +passed into the builder to grab the correct +todo from the list of items, +and then displays that todo's data in the widget that is returned from the builder. -To exemplify this, -the following example changes the +To exemplify this, +the following example changes the background color of every other list item. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/layout/alternating_list_items.png" caption:"This figure shows a `ListView`, in which its children have alternating background colors. The background colors were determined programmatically based on the index of the child within the `ListView`." code:" @@ -779,7 +779,7 @@ The following resources explain individual APIs. [`Builder`]: {{site.api}}/flutter/widgets/Builder-class.html [`ScrollView`]: {{site.api}}/flutter/widgets/Scrollview-class.html [`LayoutBuilder`]: {{site.api}}/flutter/widgets/LayoutBuilder-class.html -[`BoxConstraints`]:{{site.api}}/flutter/rendering/BoxConstraints-class.html +[`BoxConstraints`]:{{site.api}}/flutter/rendering/BoxConstraints-class.html [`LayoutBuilder`]: {{site.api}}/flutter/widgets/LayoutBuilder-class.html [`FutureBuilder`]: {{site.api}}/flutter/widgets/FutureBuilder-class.html [`Container`]:{{site.api}}/flutter/widgets/Container-class.html diff --git a/src/content/get-started/fundamentals/user-input.md b/src/content/get-started/fundamentals/user-input.md index 86a517708af..a9c49d5e9e6 100644 --- a/src/content/get-started/fundamentals/user-input.md +++ b/src/content/get-started/fundamentals/user-input.md @@ -39,7 +39,7 @@ which is covered at the end of this section. No matter which design system you choose, the principals on this page apply. ::: -> **Reference**: +> **Reference**: > The [widget catalog][] has an inventory of commonly used widgets in the [Material][] and [Cupertino][] libraries. Next, we'll cover a few of the Material widgets that support common @@ -83,7 +83,7 @@ but styled differently for various use cases, including: - `FloatingActionButton`: An icon button that hovers over content to promote a primary action. -> **Video**: +> **Video**: > [FloatingActionButton (Widget of the Week)][] There are usually 3 main aspects to constructing a button: @@ -110,10 +110,10 @@ You can style a button based on its state using `WidgetStateProperty`. - Finally, a button's `style` controls its appearance: color, border, and so on. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/ElevatedButton.webp", caption: "This figure shows an ElevatedButton with the text \"Enabled\" being clicked." -alt: "A GIF of an elevated button with the text \"Enabled\"" +alt: "A GIF of an elevated button with the text 'Enabled'" code:" ```dart int count = 0; @@ -138,7 +138,7 @@ Widget build(BuildContext context) {
-> **Checkpoint**: +> **Checkpoint**: > Complete this tutorial that teaches you how to build a > "favorite" button: [Add interactivity to your Flutter app][] @@ -165,7 +165,7 @@ Flutter's `Text` widget displays text on the screen, but doesn't allow users to highlight or copy the text. `SelectableText` displays a string of _user-selectable_ text. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/SelectableText.webp", caption: "This figure shows a cursor highlighting a portion of a string of text." alt: 'A GIF of a cursor highlighting two lines of text from a paragraph.' @@ -183,7 +183,7 @@ From forth the fatal loins of these two foes'''); ``` " %} -> **Video**: +> **Video**: > [SelectableText (Widget of the Week)][] [SelectableText (Widget of the Week)]: {{site.youtube-site}}/watch?v=ZSU3ZXOs6hc @@ -195,7 +195,7 @@ From forth the fatal loins of these two foes'''); different text styles. It's not for handling user input, but is useful if you're allowing users edit and format text. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/RichText.png", caption: "This figure shows a string of text formatted with different text styles." alt: 'A screenshot of the text "Hello bold world!" with the word "bold" in bold font.' @@ -217,10 +217,10 @@ Widget build(BuildContext context) { ``` " %} -> **Video**: +> **Video**: > [Rich Text (Widget of the Week)][] -> **Code**: +> **Code**: > [Rich Text Editor code][] [Rich Text (Widget of the Week)]: {{site.youtube-site}}/watch?v=rykDVh-QFfw @@ -251,10 +251,10 @@ The class supports other configurable properties, such as `obscureText` that turns each letter into a `readOnly` circle as its entered and `readOnly` which prevents the user from changing the text. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/TextField.webp", caption: "This figure shows text being typed into a TextField with a selected border and label." -alt: "A GIF of a text field with the label \"Mascot Name\", purple focus border and the phrase \"Dash the hummingbird\" being typed in." +alt: "A GIF of a text field with the label 'Mascot Name', purple focus border and the phrase 'Dash the hummingbird' being typed in." code:" ```dart final TextEditingController _controller = TextEditingController(); @@ -272,7 +272,7 @@ Widget build(BuildContext context) { ``` " %} -> **Checkpoint**: +> **Checkpoint**: > Complete this 4-part cookbook series that walks > you through how to create a text field, > retrieve its value, and update your app state: @@ -345,10 +345,10 @@ Widget build(BuildContext context) { > **Checkpoint**: > Complete this tutorial to learn how to [build a form with validation][]. -> **Demo**: +> **Demo**: > [Form app][] -> **Code**: +> **Code**: > [Form app code][]
@@ -395,7 +395,7 @@ A `SegmentedButton` has a few relevant properties: For example, `style` takes a `ButtonStyle`, providing a way to configure a `selectedIcon`. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/segmented-button.webp", caption: "This figure shows a SegmentedButton, each segment with an icon and text representing its value." @@ -473,7 +473,7 @@ You will typically use `Wrap`, a widget that displays its children in multiple horizontal or vertical runs, to make sure your chips wrap and don't get cut off at the edge of your app. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/chip.png", caption: "This figure shows two rows of Chip widgets, each containing a circular leading profile image and content text." @@ -543,7 +543,7 @@ Configuration parameters include the following: - Additional parameters are also available for customizing the widget's look and behavior. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/dropdownmenu.webp", caption: "This figure shows a DropdownMenu widget with 5 value options. Each option's text color is styled to represent the color value." @@ -598,7 +598,7 @@ Widget build(BuildContext context) { ``` " %} -> **Video**: +> **Video**: > [DropdownMenu (Widget of the Week)][] [DropdownMenu (Widget of the Week)]: {{site.youtube-site}}/watch?v=giV9AbM2gd8?si=E23hjg72cjMTe_mz @@ -617,12 +617,12 @@ Configuration parameters for the `Slider` widget: handle along the track. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/slider.webp", caption: "This figure shows a slider widget with a value ranging from 0.0 to 5.0 -broken up into 5 divisions. It shows the current value as a label as the dial +broken up into 5 divisions. It shows the current value as a label as the dial is dragged." -alt: "A GIF of a slider that has the dial dragged left to right in increments +alt: "A GIF of a slider that has the dial dragged left to right in increments of 1, from 0.0 to 5.0" code:" ```dart @@ -645,7 +645,7 @@ Widget build(BuildContext context) { ``` " %} -> **Video**: +> **Video**: > [Slider, RangeSlider, CupertinoSlider (Widget of the Week)][]
@@ -684,10 +684,10 @@ The configuration for `Checkbox` and `Switch` contain: ### Checkbox -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/checkbox.webp", caption: "This figure shows a checkbox being checked and unchecked." -alt: "A GIF that shows a pointer clicking a checkbox +alt: "A GIF that shows a pointer clicking a checkbox and then clicking again to uncheck it." code:" ```dart @@ -710,11 +710,11 @@ Widget build(BuildContext context) { ### Switch -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/Switch.webp", caption: "This figure shows a Switch widget that is toggled on and off." alt: "A GIF of a Switch widget that is toggled on and off. In its off state, -it is gray with dark gray borders. In its on state, +it is gray with dark gray borders. In its on state, it is red with a light red border." code:" ```dart @@ -750,7 +750,7 @@ the other radio buttons are unselected. - `Radio` also has an `onChanged` callback that gets triggered when users click it, like `Switch` and `Checkbox` -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/Radio.webp", caption: "This figure shows a column of ListTiles containing a radio button and label, where only one radio button can be selected at a time." @@ -824,7 +824,7 @@ class _RadioExampleState extends State { These convenience widgets are the same checkbox and switch widgets, but support a label (as a `ListTile`). -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/SpecialListTiles.webp", caption: "This figure shows a column containing a CheckboxListTile and a SwitchListTile being toggled." @@ -866,16 +866,16 @@ Widget build(BuildContext context) { ``` " %} -> **Video**: +> **Video**: > [CheckboxListTile (Widget of the Week)][] -> **Video**: +> **Video**: > [SwitchListTile (Widget of the Week)][]
- **API Docs**: -[`Checkbox`][] • [`CheckboxListTile`][] • [`Switch`][] • [`SwitchListTile`][] • + **API Docs**: +[`Checkbox`][] • [`CheckboxListTile`][] • [`Switch`][] • [`SwitchListTile`][] • [`Radio`][] [CheckboxListTile (Widget of the Week)]: {{site.youtube-site}}/watch?v=RkSqPAn9szs @@ -907,12 +907,12 @@ Activate by calling the `showDatePicker` function, which returns a `Future`, so don't forget to await the asynchronous function call! -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/DatePicker.webp", caption: "This figure shows a DatePicker that is displayed when the -\"Pick a date\" button is clicked." -alt: "A GIF of a pointer clicking a button that says \"Pick a date\", -then shows a date picker. The date Friday, August 30 is selected and the \"OK\" +'Pick a date' button is clicked." +alt: "A GIF of a pointer clicking a button that says 'Pick a date', +then shows a date picker. The date Friday, August 30 is selected and the 'OK' button is clicked." code:" ```dart @@ -925,7 +925,7 @@ Widget build(BuildContext context) { return Column(children: [ Text( date == null - ? \"You haven\'t picked a date yet.\" + ? 'You haven\'t picked a date yet.' : DateFormat('MM-dd-yyyy').format(date), ), ElevatedButton.icon( @@ -958,13 +958,13 @@ Instead of returning a `Future`, `showTimePicker` instead returns a `Future`. Once again, don't forget to await the function call! -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/TimePicker.webp", -caption: "This figure shows a TimePicker that is displayed when the -\"Pick a time\" button is clicked." -alt: "A GIF of a pointer clicking a button that says \"Pick a time\", then shows - a time picker. The time picker shows a circular clock as the cursor moves the - hour hand, then minute hand, selects PM, then the \"OK\" button is clicked." +caption: "This figure shows a TimePicker that is displayed when the +'Pick a time' button is clicked." +alt: "A GIF of a pointer clicking a button that says 'Pick a time', then shows + a time picker. The time picker shows a circular clock as the cursor moves the + hour hand, then minute hand, selects PM, then the 'OK' button is clicked." code:" ```dart TimeOfDay? selectedTime; @@ -975,7 +975,7 @@ Widget build(BuildContext context) { return Column(children: [ Text( - time == null ? \"You haven't picked a time yet.\" : time.format(context), + time == null ? 'You haven\'t picked a time yet.' : time.format(context), ), ElevatedButton.icon( icon: const Icon(Icons.calendar_today), @@ -999,7 +999,7 @@ Widget build(BuildContext context) { :::tip Calling `showDatePicker()` and `showTimePicker()` -is equivalent to calling `showDialog()` with `DatePickerDialog()` and +is equivalent to calling `showDialog()` with `DatePickerDialog()` and `TimePickerDialog()`, respectively. Internally, both functions use the `showDialog()` function with their respective `Dialog` widgets. @@ -1010,7 +1010,7 @@ on to the `Navigator` stack.
- **API Docs:** + **API Docs:** [`showDatePicker`][] • [`showTimePicker`][] [`showDatePicker`]: {{site.api}}/flutter/material/showDatePicker.html @@ -1029,7 +1029,7 @@ It has a number of configuration parameters, including: - It's important to include a `key` object as well so that they can be uniquely identified from sibling `Dismissible` widgets in the widget tree. -{% render docs/code-and-image.md, +{% render "docs/code-and-image.md", image:"fwe/user-input/Dismissible.webp", caption: "This figure shows a list of Dismissible widgets that each contain a ListTile. Swiping across the ListTile reveals a green background and makes the tile @@ -1067,10 +1067,10 @@ Widget build(BuildContext context) { ``` " %} -> **Video**: +> **Video**: > [Dismissible (Widget of the Week)][] -> **Checkpoint**: +> **Checkpoint**: > Complete this tutorial on how to [implement swipe to dismiss][] using the > dismissible widget. @@ -1090,7 +1090,7 @@ you can use for handling user input in your Flutter app. Check out the [Material Widget library][] and [Material Library API docs][] for a full list of widgets. -> **Demo**: +> **Demo**: > See Flutter's [Material 3 Demo][] for a curated sample of user input widgets > available in the Material library. @@ -1101,7 +1101,7 @@ For example, the [`flutter_slidable`][] package provides a `Slidable` widget that is more customizable than the `Dismissible` widget described in the previous section. -> **Video**: +> **Video**: > [flutter_slidable (Package of the Week)][] [Material Widget Library]: /ui/widgets/material @@ -1119,18 +1119,18 @@ fits the user interaction that you're looking for? You can build your own custom widget and make it interactive using `GestureDetector`. -> **Checkpoint**: +> **Checkpoint**: > Use this recipe as a starting point to create your own _custom_ button widget > that can [handle taps][]. -> **Video**: +> **Video**: > [GestureDetector (Widget of the Week)][] -> **Reference**: +> **Reference**: > Check out [Taps, drags, and other gestures][] which explains how to listen > for, and respond to, gestures in Flutter. -> **Bonus Video**: +> **Bonus Video**: > Curious how Flutter's `GestureArena` turns raw user interaction data into > human recognizable concepts like taps, drags, and pinches? > Check out this video: [GestureArena (Decoding Flutter)][] @@ -1147,7 +1147,7 @@ annotate its meaning with the `Semantics` widget. It provides descriptions and metadata to screen readers and other semantic analysis-based tools. -> **Video**: +> **Video**: > [Semantics (Flutter Widget of the Week)][] @@ -1168,11 +1168,11 @@ ensure that everything works as expected! These tutorials walk you through writing tests that simulate user interactions in your app: -> **Checkpoint**: +> **Checkpoint**: > Follow this [tap, drag, and enter text][] cookbook article and learn how to > use `WidgetTester` to simulate and test user interactions in your app. -> **Bonus Tutorial**: +> **Bonus Tutorial**: > The [handle scrolling][] cookbook recipe shows you how to verify that > lists of widgets contain the expected content by > scrolling through the lists using widget tests. diff --git a/src/content/get-started/index.md b/src/content/get-started/index.md index 18cf5de5a50..e2669158267 100644 --- a/src/content/get-started/index.md +++ b/src/content/get-started/index.md @@ -39,4 +39,4 @@ your Flutter development environment.
-{% render docs/china-notice.md %} +{% render "docs/china-notice.md" %} diff --git a/src/content/get-started/learn-flutter.md b/src/content/get-started/learn-flutter.md index ea8f9809ec5..082b1ebea05 100644 --- a/src/content/get-started/learn-flutter.md +++ b/src/content/get-started/learn-flutter.md @@ -4,7 +4,7 @@ description: Resources to help you learn Flutter. showToc: false --- -{% ytEmbed 'W4JWeQolJsU', 'Build and ship amazing multiplatform iOS and Android apps with one codebase', true %} + ## For new Flutter developers diff --git a/src/content/get-started/quick.md b/src/content/get-started/quick.md index 7048847b5da..4140be2bc2f 100644 --- a/src/content/get-started/quick.md +++ b/src/content/get-started/quick.md @@ -35,7 +35,7 @@ installing and trying out Flutter on a **Windows**{:.selected-os-text} device. If you'd like to follow the instructions for a different OS, please select one of the following. -{% osSelector %} + ## Download prerequisite software {: #download-prerequisites} @@ -89,7 +89,7 @@ first install the following tools. step: Download and install Visual Studio Code.** There are a few ways to install git on your Mac, - but the way we recommend is by using XCode. + but the way we recommend is by using XCode. This will be important when you target your builds for iOS or macOS. @@ -418,7 +418,7 @@ follow the codelab on [Building your first app][], set up development for an [additional target platform][], or explore some of these resources to continue your Flutter learning journey. -{% render docs/get-started/setup-next-steps.html, site: site %} +{% render "docs/get-started/setup-next-steps.html", site: site %} [Building your first app]: /get-started/codelab [additional target platform]: /platform-integration#setup diff --git a/src/content/index.md b/src/content/index.md index ba9cdc42275..80d6dee03e6 100644 --- a/src/content/index.md +++ b/src/content/index.md @@ -8,14 +8,9 @@ description: >-
{% for card in docsCards -%} - -
- {{card.name}} -
-
-

{{card.description}}

-
-
+ + {{card.description}} + {% endfor -%}
@@ -30,10 +25,10 @@ Ready to build beautiful, multiplatform apps from a single codebase? This video walks you through the fundamentals of Flutter and shows you how to get started. Once you've [Set up Flutter][], -you should follow the -[Write your first Flutter app][] codelab -and read [Flutter fundamentals][]. -These resources are opinionated documentation +you should follow the +[Write your first Flutter app][] codelab +and read [Flutter fundamentals][]. +These resources are opinionated documentation that guide you through the most important parts of building a Flutter app. @@ -75,24 +70,25 @@ Coming from another platform? Check out Flutter for: ### Videos -{% videoWrapper 'Check out what\'s new in Flutter at Google I/O 2025!' %} -{% ytEmbed 'v6Rzo5khNE8', 'What\'s new in Flutter', true %} -{% endvideoWrapper %} +
+ Check out what's new in Flutter at Google I/O 2025! + +

For more Flutter at Google I/O 2025, check out -[How to build agentic apps with Flutter and Firebase AI Logic][] +[How to build agentic apps with Flutter and Firebase AI Logic][] and [How Flutter makes the most of your platforms][].
- {% ytEmbed 'xo271p-Fl_4', 'How to build agentic apps with Flutter and Firebase AI Logic', true %} +
- {% ytEmbed 'flwULzNYRac', 'How Flutter makes the most of your platforms', true %} +
diff --git a/src/content/install/add-to-path.md b/src/content/install/add-to-path.md index 93f2e3fec2e..d4c0c94a997 100644 --- a/src/content/install/add-to-path.md +++ b/src/content/install/add-to-path.md @@ -57,25 +57,25 @@ follow [Set up and test drive Flutter][] instead. To run `flutter` and `dart` commands in a terminal on Windows, add the Flutter SDK's `bin` directory to the `Path` environment variable. -{% render docs/install/path/windows.md %} +{% render "docs/install/path/windows.md" %} ## macOS To run `flutter` and `dart` commands in a terminal on macOS, add the Flutter SDK's `bin` directory to the `PATH` environment variable. -{% render docs/install/path/macos.md %} +{% render "docs/install/path/macos.md" %} ## Linux To run `flutter` and `dart` commands in a terminal on Linux, add the Flutter SDK's `bin` directory to the `PATH` environment variable. -{% render docs/install/path/linux.md %} +{% render "docs/install/path/linux.md" %} ## ChromeOS To run `flutter` and `dart` commands in a terminal on chromeOS, add the Flutter SDK's `bin` directory to the `PATH` environment variable. -{% render docs/install/path/chromeos.md %} +{% render "docs/install/path/chromeos.md" %} diff --git a/src/content/install/archive.md b/src/content/install/archive.md index 9073ae6bce2..7e6980a6254 100644 --- a/src/content/install/archive.md +++ b/src/content/install/archive.md @@ -4,7 +4,7 @@ shortTitle: Archive description: "All current Flutter SDK releases: stable, beta, and main." --- -{% render docs/china-notice.md %} +{% render "docs/china-notice.md" %} ## Overview @@ -15,15 +15,15 @@ version of Flutter for compatibility reasons or to investigate bugs. The archive includes Flutter SDKs for Windows, macOS, and Linux on the following [channels][]: -* **{{site.sdk.channel | capitalize }} channel**: This channel contains the - most stable Flutter builds. Roughly every third beta version is promoted - to the stable version. The stable channel is the recommended channel for +* **Stable channel**: This channel contains the most stable Flutter builds. + Roughly every third beta version is promoted to the stable version. + The stable channel is the recommended channel for new users and for production app releases. * **Beta channel**: This channel is the most recent version of Flutter that is available, but it is not yet stable. The beta branch is usually released on the first Wednesday of the month. A fix will typically end up in the - beta channel about two weeks after it lands in the main channel. + beta channel about two weeks after it lands in the main channel. Releases are distributed as [installation bundles][]. * **Main channel**: This channel has the newest features, but it hasn't been fully @@ -55,53 +55,31 @@ SDK archive: ## Stable channel -{% tabs "os-archive-tabs" %} - -{% tab "Windows" %} - -{% render docs/release/archive-release.md, os: "Windows", channel: "stable" %} - -{% endtab %} - -{% tab "macOS" %} - -{% render docs/release/archive-release.md, os: "macOS", channel: "stable" %} - -{% endtab %} - -{% tab "Linux" %} - -{% render docs/release/archive-release.md, os: "Linux", channel: "stable" %} - -{% endtab %} - -{% endtabs %} - + + + + + + + + + + + ## Beta channel -{% tabs "os-archive-tabs" %} - -{% tab "Windows" %} - -{% render docs/release/archive-release.md, os: "Windows", channel: "beta" %} - -{% endtab %} - -{% tab "macOS" %} - -{% render docs/release/archive-release.md, os: "macOS", channel: "beta" %} - -{% endtab %} - -{% tab "Linux" %} - -{% render docs/release/archive-release.md, os: "Linux", channel: "beta" %} - -{% endtab %} - -{% endtabs %} - + + + + + + + + + + + diff --git a/src/content/install/manual.md b/src/content/install/manual.md index cd4b359804f..65588f811cd 100644 --- a/src/content/install/manual.md +++ b/src/content/install/manual.md @@ -29,7 +29,7 @@ installing Flutter on a **Windows**{:.selected-os-text} device. If you'd like to follow the instructions for a different OS, please select one of the following. -{% osSelector %} + ## Download prerequisite software {: #download-prerequisites} @@ -156,7 +156,7 @@ then extract the SDK to where you want it stored. Download the following installation bundle to get the latest stable release of the Flutter SDK. - [(loading...)](#){:.download-latest-link-windows .filled-button} + 1.

Create a folder to store the SDK

@@ -203,9 +203,9 @@ then extract the SDK to where you want it stored. download one of the following installation bundles to get the latest stable release of the Flutter SDK. - | Apple Silicon (ARM64) | Intel (x64) | - |-------------------------------------------------------------------------------------|----------------------------------------------------------------| - | [(loading...)](#){:.download-latest-link-macos-arm64 .apple-silicon .filled-button} | [(loading...)](#){:.download-latest-link-macos .filled-button} | + | Apple Silicon (ARM64) | Intel | + |--------------------------------------------------|------------------------------------------------| + | | | 1.

Create a folder to store the SDK

@@ -242,7 +242,7 @@ then extract the SDK to where you want it stored. Download the following installation bundle to get the latest stable release of the Flutter SDK. - [(loading...)](#){:.download-latest-link-linux .filled-button} + 1.

Create a folder to store the SDK

@@ -283,25 +283,25 @@ Adding Flutter to your `PATH` allows you to use the
-{% render docs/install/path/windows.md %} +{% render "docs/install/path/windows.md" %}
-{% render docs/install/path/macos.md %} +{% render "docs/install/path/macos.md" %}
-{% render docs/install/path/linux.md %} +{% render "docs/install/path/linux.md" %}
-{% render docs/install/path/chromeos.md %} +{% render "docs/install/path/chromeos.md" %}
diff --git a/src/content/install/uninstall.md b/src/content/install/uninstall.md index ccc58adb6b2..8450d54fe7f 100644 --- a/src/content/install/uninstall.md +++ b/src/content/install/uninstall.md @@ -17,7 +17,7 @@ uninstall Flutter on a **Windows**{:.selected-os-text} device. If you'd like to follow the instructions for a different OS, please select one of the following. -{% osSelector %} + ## Uninstall the Flutter SDK {: #uninstall } diff --git a/src/content/install/with-vs-code.md b/src/content/install/with-vs-code.md index 05f89c35ea4..0e42a56c576 100644 --- a/src/content/install/with-vs-code.md +++ b/src/content/install/with-vs-code.md @@ -28,7 +28,7 @@ installing Flutter on a **Windows**{:.selected-os-text} device. If you'd like to follow the instructions for a different OS, please select one of the following. -{% osSelector %} + ## Download prerequisite software {: #download-prerequisites} diff --git a/src/content/packages-and-plugins/swift-package-manager/for-app-developers.md b/src/content/packages-and-plugins/swift-package-manager/for-app-developers.md index 8e623c28a39..150a9fccbb1 100644 --- a/src/content/packages-and-plugins/swift-package-manager/for-app-developers.md +++ b/src/content/packages-and-plugins/swift-package-manager/for-app-developers.md @@ -16,7 +16,7 @@ Flutter continues to support CocoaPods. Flutter's Swift Package Manager integration has several benefits: 1. **Provides access to the Swift package ecosystem**. - Flutter plugins can use the growing ecosystem of [Swift packages][]. + Flutter plugins can use the growing ecosystem of [Swift packages][]. 1. **Simplifies Flutter installation**. Xcode includes Swift Package Manager. You don't need to install Ruby and CocoaPods if your project uses @@ -27,39 +27,39 @@ Flutter's Swift Package Manager integration has several benefits: [Swift packages]: https://swiftpackageindex.com/ [open an issue]: {{site.github}}/flutter/flutter/issues/new?template=2_bug.yml -{% render docs/swift-package-manager/how-to-enable-disable.md, site: site %} +{% render "docs/swift-package-manager/how-to-enable-disable.md", site: site %} ## How to add Swift Package Manager integration ### Add to a Flutter app -{% tabs %} -{% tab "iOS project" %} + + -{% render docs/swift-package-manager/migrate-ios-project.md, site: site %} +{% render "docs/swift-package-manager/migrate-ios-project.md", site: site %} -{% endtab %} -{% tab "macOS project" %} + + -{% render docs/swift-package-manager/migrate-macos-project.md, site: site %} +{% render "docs/swift-package-manager/migrate-macos-project.md", site: site %} -{% endtab %} -{% endtabs %} + + ### Add to a Flutter app _manually_ -{% tabs %} -{% tab "iOS project" %} + + -{% render docs/swift-package-manager/migrate-ios-project-manually.md, site: site %} +{% render "docs/swift-package-manager/migrate-ios-project-manually.md", site: site %} -{% endtab %} -{% tab "macOS project" %} + + -{% render docs/swift-package-manager/migrate-macos-project-manually.md, site: site %} +{% render "docs/swift-package-manager/migrate-macos-project-manually.md", site: site %} -{% endtab %} -{% endtabs %} + + ### Add to an existing app (add-to-app) @@ -112,7 +112,7 @@ To undo this migration: 1. Click the `FlutterGeneratedPluginSwiftPackage` package, then click remove. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/remove-generated-package.png", caption:"The `FlutterGeneratedPluginSwiftPackage` to remove" %} + 1. Navigate to **Frameworks, Libraries, and Embedded Content** for the `Runner` target. @@ -120,7 +120,7 @@ To undo this migration: 1. Click `FlutterGeneratedPluginSwiftPackage`, then click the remove. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/remove-generated-framework.png", caption:"The `FlutterGeneratedPluginSwiftPackage` to remove" %} + 1. Go to **Product > Scheme > Edit Scheme**. @@ -132,7 +132,7 @@ To undo this migration: 1. Click **delete**. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/remove-flutter-pre-action.png", caption:"The build pre-action to remove" %} + [Turn off Swift Package Manager]: /packages-and-plugins/swift-package-manager/for-app-developers/#how-to-turn-off-swift-package-manager @@ -152,7 +152,7 @@ To use the plugin: 1. Increase your app's target **Minimum Deployments**. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/minimum-deployments.png", caption:"The target's **Minimum Deployments** setting" %} + 1. If you updated your iOS app's **Minimum Deployments**, regenerate the iOS project's configuration files: diff --git a/src/content/packages-and-plugins/swift-package-manager/for-plugin-authors.md b/src/content/packages-and-plugins/swift-package-manager/for-plugin-authors.md index e23b926c50e..5c9817d711d 100644 --- a/src/content/packages-and-plugins/swift-package-manager/for-plugin-authors.md +++ b/src/content/packages-and-plugins/swift-package-manager/for-plugin-authors.md @@ -16,7 +16,7 @@ Flutter continues to support CocoaPods. Flutter's Swift Package Manager integration has several benefits: 1. **Provides access to the Swift package ecosystem**. - Flutter plugins can use the growing ecosystem of [Swift packages][]! + Flutter plugins can use the growing ecosystem of [Swift packages][]! 1. **Simplifies Flutter installation**. Swift Package Manager is bundled with Xcode. In the future, you won’t need to install Ruby and CocoaPods to target iOS or @@ -28,7 +28,7 @@ Flutter's Swift Package Manager integration has several benefits: [Swift packages]: https://swiftpackageindex.com/ [open an issue]: {{site.github}}/flutter/flutter/issues/new?template=2_bug.yml -{% render docs/swift-package-manager/how-to-enable-disable.md, site: site %} +{% render "docs/swift-package-manager/how-to-enable-disable.md", site: site %} ## How to add Swift Package Manager support to an existing Flutter plugin @@ -46,18 +46,18 @@ Plugins that don't support Swift Package Manager can cause problems for projects that have migrated. -{% tabs %} -{% tab "Swift plugin" %} + + -{% render docs/swift-package-manager/migrate-swift-plugin.md, site: site %} +{% render "docs/swift-package-manager/migrate-swift-plugin.md", site: site %} -{% endtab %} -{% tab "Objective-C plugin" %} + + -{% render docs/swift-package-manager/migrate-objective-c-plugin.md, site: site %} +{% render "docs/swift-package-manager/migrate-objective-c-plugin.md", site: site %} -{% endtab %} -{% endtabs %} + + ## How to update unit tests in a plugin's example app @@ -77,7 +77,7 @@ To update your unit tests: ```ruby title="ios/Podfile" diff target 'RunnerTests' do inherit! :search_paths - + - pod 'OCMock', '3.5' end ``` @@ -87,12 +87,12 @@ To update your unit tests: 1. Navigate to **Package Dependencies** for the project. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/package-dependencies.png", caption:"The project's package dependencies" %} + 1. Click the **+** button and add any test-only dependencies by searching for them in the top right search bar. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/search-for-ocmock.png", caption:"Search for test-only dependencies" %} + :::note OCMock uses unsafe build flags and can only be used if targeted by commit. @@ -102,7 +102,7 @@ To update your unit tests: 1. Ensure the dependency is added to the `RunnerTests` Target. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/choose-package-products-test.png", caption:"Ensure the dependency is added to the `RunnerTests` target" %} + 1. Click the **Add Package** button. @@ -114,13 +114,13 @@ To update your unit tests: 1. Ensure `RunnerTests` **Build Phases** has a **Link Binary With Libraries** build phase: - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/runner-tests-link-binary-with-libraries.png", caption:"The `Link Binary With Libraries` Build Phase in the `RunnerTests` target" %} + If the build phase doesn't exist already, create one. Click the add and then click **New Link Binary With Libraries Phase**. - {% render docs/captioned-image.liquid, image:"development/packages-and-plugins/swift-package-manager/add-runner-tests-link-binary-with-libraries.png", caption:"Add `Link Binary With Libraries` Build Phase" %} + 1. Navigate to **Package Dependencies** for the project. diff --git a/src/content/packages-and-plugins/using-packages.md b/src/content/packages-and-plugins/using-packages.md index d0e8a8ea8c7..5cd0e6e1776 100644 --- a/src/content/packages-and-plugins/using-packages.md +++ b/src/content/packages-and-plugins/using-packages.md @@ -33,7 +33,7 @@ which is generally shortened to _plugin_. For example, a plugin might provide Flutter apps with the ability to use a device's camera. -{% ytEmbed 'Y9WifT8aN6o', 'Packages versus plugins | Decoding Flutter' %} + ::: Existing packages enable many use cases—for example, diff --git a/src/content/perf/app-size.md b/src/content/perf/app-size.md index 6e1bac1eeda..47d08b494cc 100644 --- a/src/content/perf/app-size.md +++ b/src/content/perf/app-size.md @@ -55,7 +55,7 @@ dropping the .aab file. View the application's download and install size in the **Android vitals** -> **App size** tab. -{% render docs/app-figure.md, image:"perf/vital-size.png", alt:"App size tab in Google Play Console" %} + The download size is calculated based on an XXXHDPI (~640dpi) device on an arm64-v8a architecture. Your end users' download sizes might vary depending on @@ -144,7 +144,7 @@ In addition to analyzing a single build, two builds can also be diffed by loading two `*-code-size-analysis_*.json` files into DevTools. Check out the [DevTools documentation][] for details. -{% render docs/app-figure.md, image:"perf/size-summary.png", alt:"Size summary of an Android application in terminal" %} + Through the summary, you can get a quick idea of the size usage per category (such as asset, native code, Flutter libraries, etc). The compiled Dart @@ -167,7 +167,7 @@ up to function level for the Dart AOT artifact. This can be done by `dart devtools`, selecting `Open app size tool` and uploading the JSON file. -{% render docs/app-figure.md, image:"perf/devtools-size.png", alt:"Example breakdown of app in DevTools" %} + For further information on using the DevTools app size tool, check out the [DevTools documentation][]. diff --git a/src/content/perf/best-practices.md b/src/content/perf/best-practices.md index 50f2087f745..b8e1c3894c9 100644 --- a/src/content/perf/best-practices.md +++ b/src/content/perf/best-practices.md @@ -4,7 +4,7 @@ shortTitle: Best practices description: How to ensure that your Flutter app is performant. --- -{% render docs/performance.md %} +{% render "docs/performance.md" %} Generally, Flutter applications are performant by default, so you only need to avoid common pitfalls to get excellent @@ -90,7 +90,7 @@ For more information, check out: * [Performance considerations][], part of the [`StatefulWidget`][] API doc * [Widgets vs helper methods][], - a video from the official Flutter YouTube + a video from the official Flutter YouTube channel that explains why widgets (especially widgets with `const` constructors) are more performant than functions. @@ -108,13 +108,13 @@ For more information, check out: ### Use StringBuffer for efficient string building -When you need to build a string from multiple parts, especially inside a loop, -using the `+` operator can be inefficient because it creates a new `String` -object on each concatenation. A better approach is to use `StringBuffer`, -which collects all the strings and concatenates them only once, when you call +When you need to build a string from multiple parts, especially inside a loop, +using the `+` operator can be inefficient because it creates a new `String` +object on each concatenation. A better approach is to use `StringBuffer`, +which collects all the strings and concatenates them only once, when you call `toString()`. -{% ytEmbed 'xSsFtDY-nOw', 'StringBuffer (Technique of the Week)' %} + --- @@ -171,7 +171,7 @@ create your visual effects: in the same way, with the same transparency, you can precalculate what this overlapped, semi-transparent object looks like, cache it, - and use that instead of calling `saveLayer()`. + and use that instead of calling `saveLayer()`. This works with any static shape you can precalculate. * Can you refactor your painting logic to avoid overlaps altogether? @@ -246,7 +246,7 @@ Here are some tips you might find to be useful: --- -### Implement grids and lists thoughtfully +### Implement grids and lists thoughtfully How your grids and lists are implemented might be causing performance problems for your app. @@ -313,7 +313,7 @@ that the widget prefers, assuming no constraints. With this information, the framework determines a uniform cell size, and re-visits all grid cells a second time, -telling each card what size to use. +telling each card what size to use. #### Debugging intrinsic passes @@ -422,7 +422,7 @@ your app's performance. of children (such as `Column()` or `ListView()`) if most of the children are not visible on screen to avoid the build cost. - + * Avoid overriding `operator ==` on `Widget` objects. While it might seem like it would help by avoiding unnecessary rebuilds, in practice it hurts performance because it results in O(N²) behavior. diff --git a/src/content/perf/impeller.md b/src/content/perf/impeller.md index 506bef1c3b0..216bd0c80ce 100644 --- a/src/content/perf/impeller.md +++ b/src/content/perf/impeller.md @@ -23,7 +23,7 @@ at engine-build time so they don't compile at runtime. For a video introduction to Impeller, check out the following talk from Google I/O 2023. -{% ytEmbed 'vd5NqS01rlA', 'Introducing Impeller, Flutter\'s new rendering engine' %} + Impeller has the following objectives: diff --git a/src/content/perf/index.md b/src/content/perf/index.md index 2f0769e388e..c61f5b51811 100644 --- a/src/content/perf/index.md +++ b/src/content/perf/index.md @@ -3,7 +3,7 @@ title: Performance description: Evaluating the performance of your app from several angles. --- -{% ytEmbed 'PKGguGUwSYE', 'Flutter performance tips | Flutter in Focus' %} + :::note If your app has a performance issue and you are diff --git a/src/content/perf/isolates.md b/src/content/perf/isolates.md index 0819fa5b05d..382539cf4c1 100644 --- a/src/content/perf/isolates.md +++ b/src/content/perf/isolates.md @@ -64,7 +64,7 @@ documentation. [concurrency page]: {{site.dart-site}}/language/concurrency -{% ytEmbed 'vl_AaCgudcY', 'Isolates and the event loop | Flutter in Focus' %} + ## Common use cases for isolates diff --git a/src/content/perf/rendering-performance.md b/src/content/perf/rendering-performance.md index eb161e4b6dd..2bccfdb4dbd 100644 --- a/src/content/perf/rendering-performance.md +++ b/src/content/perf/rendering-performance.md @@ -3,7 +3,7 @@ title: Improving rendering performance description: How to measure and evaluate your app's rendering performance. --- -{% render docs/performance.md %} +{% render "docs/performance.md" %} Rendering animations in your app is one of the most cited topics of interest when it comes to measuring performance. diff --git a/src/content/platform-integration/android/c-interop.md b/src/content/platform-integration/android/c-interop.md index 0d750097b65..5301c84041b 100644 --- a/src/content/platform-integration/android/c-interop.md +++ b/src/content/platform-integration/android/c-interop.md @@ -84,7 +84,7 @@ $ cd native_add :::note You can exclude platforms from `--platforms` that you don't want -to build to. However, you need to include the platform of +to build to. However, you need to include the platform of the device you are testing on. ::: @@ -206,4 +206,4 @@ in the following way. [Android guidelines]: {{site.android-dev}}/topic/performance/reduce-apk-size#extract-false -{% render docs/resource-links/ffi-video-resources.md, site: site %} +{% render "docs/resource-links/ffi-video-resources.md", site: site %} diff --git a/src/content/platform-integration/android/platform-views.md b/src/content/platform-integration/android/platform-views.md index c1ca18cd8ea..37b780ea3de 100644 --- a/src/content/platform-integration/android/platform-views.md +++ b/src/content/platform-integration/android/platform-views.md @@ -27,7 +27,7 @@ see [Hosting native macOS views][]. [Hosting native macOS views]: /platform-integration/macos/platform-views Platform Views on Android have two implementations. They come with tradeoffs -both in terms of performance and fidelity. +both in terms of performance and fidelity. Platform views require Android API 23+. ## [Hybrid Composition](#hybrid-composition) @@ -67,7 +67,7 @@ In your Dart file, for example `native_view_example.dart`, use the following instructions: -1. Add the following imports: +1. Add the following imports: ```dart @@ -76,8 +76,8 @@ use the following instructions: import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; - ``` - + ``` + 2. Implement a `build()` method: @@ -170,8 +170,8 @@ On the platform side, use the standard `io.flutter.plugin.platform` package in either Kotlin or Java: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + In your native code, implement the following: @@ -245,7 +245,7 @@ class MainActivity : FlutterActivity() { flutterEngine .platformViewsController .registry - .registerViewFactory("", + .registerViewFactory("", NativeViewFactory()) } } @@ -272,8 +272,8 @@ class PlatformViewPlugin : FlutterPlugin { } ``` -{% endtab %} -{% tab "Java" %} + + In your native code, implement the following: @@ -392,8 +392,8 @@ public class PlatformViewPlugin implements FlutterPlugin { } ``` -{% endtab %} -{% endtabs %} + + For more information, see the API docs for: @@ -418,7 +418,7 @@ android { } } ``` -### Surface Views +### Surface Views Handling SurfaceViews is problematic for Flutter and should be avoided when possible. @@ -429,14 +429,13 @@ Some example views include `SurfaceView` and `SurfaceTexture`. When your Platform View includes these views you are required to manually invalidate the view after they have been drawn to (or more specifically: after the swap chain is flipped). -Manual view invalidation is done by calling `invalidate` on the View +Manual view invalidation is done by calling `invalidate` on the View or one of its parent views. [`AndroidViewSurface`]: {{site.api}}/flutter/widgets/AndroidViewSurface-class.html -### Issues +### Issues [Existing Platform View issues](https://github.com/flutter/flutter/issues?q=is%3Aopen+is%3Aissue+label%3A%22a%3A+platform-views%22) -{% render docs/platform-view-perf.md, site: site %} - +{% render "docs/platform-view-perf.md", site: site %} diff --git a/src/content/platform-integration/android/setup.md b/src/content/platform-integration/android/setup.md index 07780b8b076..575ff54fe02 100644 --- a/src/content/platform-integration/android/setup.md +++ b/src/content/platform-integration/android/setup.md @@ -27,7 +27,7 @@ setting up Android development on a **Windows**{:.selected-os-text} device. If you'd like to follow the instructions for a different OS, please select one of the following. -{% osSelector %} + ## Set up Android tooling {: #set-up-tooling} @@ -154,8 +154,8 @@ install and set up the latest stable version of [Android Studio][]. You can debug Flutter apps on physical Android devices or by running them on an Android emulator. -{% tabs "android-emulator-or-not" %} -{% tab "Android emulator" %} + + To set up your development environment to run a Flutter app on an Android emulator, follow these steps: @@ -235,8 +235,8 @@ run a Flutter app on an Android emulator, follow these steps: [hardware acceleration]: {{site.android-dev}}/studio/run/emulator-acceleration [Create and manage virtual devices]: {{site.android-dev}}/studio/run/managing-avds -{% endtab %} -{% tab "Physical device" %} + + To set up your development environment to run a Flutter app on a physical Android device, follow these steps: @@ -282,8 +282,8 @@ run a Flutter app on a physical Android device, follow these steps: [Connect to your device using Wi-Fi]: {{site.android-dev}}/studio/run/device#wireless [Install OEM USB drivers]: {{site.android-dev}}/studio/run/oem-usb -{% endtab %} -{% endtabs %} + + ## Validate your setup {: #validate-setup} diff --git a/src/content/platform-integration/android/splash-screen.md b/src/content/platform-integration/android/splash-screen.md index ff29ac95318..3acb2f9ea98 100644 --- a/src/content/platform-integration/android/splash-screen.md +++ b/src/content/platform-integration/android/splash-screen.md @@ -8,10 +8,10 @@ description: Learn how to add a splash screen to your Android app. ## Overview -A splash screens (also known as a launch screen) provides -a simple initial experience while your Android app loads. -It sets the stage for your application, -while allowing time for the app engine +A splash screens (also known as a launch screen) provides +a simple initial experience while your Android app loads. +It sets the stage for your application, +while allowing time for the app engine to load and your app to initialize. You have a couple options for implementing a splash screen: @@ -121,7 +121,7 @@ If your Android app supports releases earlier than Android 12 _and_ post-Android 12 releases, consider using two different resources in your `styles.xml` file. Also, make sure that your background image is in line with -the icon guidelines. For more information, +the icon guidelines. For more information, visit [Android Splash Screens][]. ::: @@ -135,8 +135,8 @@ while additional loading continues in Dart. To achieve this, the following Android APIs might be helpful: -{% tabs "android-language" %} -{% tab "Kotlin" %} + + ```kotlin title="MainActivity.kt" import android.os.Build @@ -160,8 +160,8 @@ class MainActivity : FlutterActivity() { } ``` -{% endtab %} -{% tab "Java" %} + + ```java title="MainActivity.java" import android.os.Build; @@ -191,8 +191,8 @@ public class MainActivity extends FlutterActivity { } ``` -{% endtab %} -{% endtabs %} + + Then, you can reimplement the first frame in Flutter that shows elements of your Android launch screen in diff --git a/src/content/platform-integration/ios/app-extensions.md b/src/content/platform-integration/ios/app-extensions.md index 5ba361975d2..31075a0d1f8 100644 --- a/src/content/platform-integration/ios/app-extensions.md +++ b/src/content/platform-integration/ios/app-extensions.md @@ -54,7 +54,7 @@ an existing project. * In the Xcode menu bar, select **File** > **New** > **Target**. - + * Add **Share Extension**. * In the **Name field**, enter **ShareExtension**. @@ -68,7 +68,7 @@ an existing project. * Open the **project navigator** (**View** > **Navigators** > **Project**). - + * In the **project navigator**, at the top, select **Runner**. @@ -86,7 +86,7 @@ an existing project. * Open the **project navigator** (**View** > **Navigators** > **Project**). - + * In the **project navigator**, at the top, select **Runner**. @@ -126,9 +126,9 @@ The following steps assume you're using the sample application and Share extension from [Adding iOS app extensions][]. -{% tabs "register-plugins-tabs", true %} + -{% tab "Simulator" %} + 1. In Xcode, [add an app extension to your project][]. @@ -147,9 +147,9 @@ application and Share extension from * Select a photo, tap the share button, then tap on the share extension icon of your app. -{% endtab %} + -{% tab "Physical device" %} + 1. Add an app extension to your project. @@ -163,13 +163,13 @@ application and Share extension from * Launch an app that supports the Share extension, such as the Photos app. - + * Select a photo, tap the share button, then tap on the share extension icon of your app. -{% endtab %} + -{% endtabs %} + [Adding iOS app extensions]: #add-extension [add an app extension to your project]: #add-extension @@ -187,7 +187,7 @@ to communicate with each other. ### Use higher-level APIs {: #using-higher-level-apis } -Some extensions have APIs. For example, +Some extensions have APIs. For example, the [Core Spotlight][] framework indexes your app, allowing users to search from Spotlight and Safari. The [WidgetKit][] framework can trigger an update @@ -226,7 +226,7 @@ To add a target to an App Group: 1. Select an App Group from the list. 1. Click **+** to add a new App Group. -{% render docs/app-figure.md, image:"development/platform-integration/app-extensions/xcode-app-groups.png", alt:"Selecting an App Group within an Xcode Runner target configuration." %} + When two targets belong to the same App Group, they can read from and write to the same source. @@ -302,7 +302,7 @@ called `Runner`, and the Flutter app is called 1. In the console, navigate to your Flutter project directory and then open your project in Xcode - with the following command: + with the following command: ```console open ios/Runner.xcworkspace @@ -365,7 +365,7 @@ called `Runner`, and the Flutter app is called * Repeat the previous step for **Profile**, and **Release**. - + * When you are finished, make sure that the configurations look similar to the following: @@ -403,9 +403,8 @@ called `Runner`, and the Flutter app is called * Update `ShareViewController` to use the `FlutterViewController` class: -{% tabs "controller-code-tabs", true %} - -{% tab "UIKit-Swift" %} + + ```swift title="ShareViewController.swift" import UIKit @@ -434,9 +433,9 @@ class ShareViewController: UIViewController { } ``` -{% endtab %} + -{% tab "UIKit-ObjC" %} + ```objc title="ShareViewController.h" @import Flutter; @@ -474,9 +473,9 @@ class ShareViewController: UIViewController { @end ``` -{% endtab %} + -{% endtabs %} + 8. [Test your app with the simulator][]. @@ -501,7 +500,7 @@ called `Runner`, and the Flutter app is called * Open the **project navigator** (**View** > **Navigators** > **Project**). - * In the main window under **TARGETS**, select + * In the main window under **TARGETS**, select **ShareExtension**. * Open the **Build Phases** tab. @@ -544,18 +543,18 @@ called `Runner`, and the Flutter app is called * Update the `ShareViewController` file to use the `GeneratedPluginRegistrant.h`: -{% tabs "register-plugins-tabs", true %} + -{% tab "UIKit-Swift" %} + ```swift title="ShareViewController.swift" // Add this inside `showFlutter()` at the top GeneratedPluginRegistrant.register(with: flutterEngine) ``` -{% endtab %} + -{% tab "UIKit-ObjC" %} + ```objc title="ShareViewController.m" // Add this import at the top @@ -567,9 +566,9 @@ GeneratedPluginRegistrant.register(with: flutterEngine) [GeneratedPluginRegistrant registerWithRegistry:flutterEngine]; ``` -{% endtab %} + -{% endtabs %} + 5. (Xcode) [Test your app with the simulator][]. @@ -591,16 +590,16 @@ GeneratedPluginRegistrant.register(with: flutterEngine) It is advisable to only modify an app extension's UI if the app extension supports at least 100MB of memory. -## Call Dart code / render Flutter content in iOS app extensions +## Call Dart code / render Flutter content in iOS app extensions The [home_widget][] package provides a large amount of functionality, which includes allowing the following: -* [Respond to user input][] in app extensions +* [Respond to user input][] in app extensions using Dart Code. - + * [Render Flutter widgets][] in an app extension as an image. - + * [Save and retrieve data][] from `UserDefaults` on iOS. ## Other resources {: #other-resources } diff --git a/src/content/platform-integration/ios/c-interop.md b/src/content/platform-integration/ios/c-interop.md index 577e46e60be..abfb4bc3d57 100644 --- a/src/content/platform-integration/ios/c-interop.md +++ b/src/content/platform-integration/ios/c-interop.md @@ -75,7 +75,7 @@ $ cd native_add :::note You can exclude platforms from `--platforms` that you don't want -to build to. However, you need to include the platform of +to build to. However, you need to include the platform of the device you are testing on. ::: @@ -217,4 +217,4 @@ the symbols are stripped by Xcode. 1. In Xcode, go to **Target Runner > Build Settings > Strip Style**. 2. Change from **All Symbols** to **Non-Global Symbols**. -{% render docs/resource-links/ffi-video-resources.md, site: site %} +{% render "docs/resource-links/ffi-video-resources.md", site: site %} diff --git a/src/content/platform-integration/ios/ios-app-clip.md b/src/content/platform-integration/ios/ios-app-clip.md index 84c361cb299..e0ac1be4c64 100644 --- a/src/content/platform-integration/ios/ios-app-clip.md +++ b/src/content/platform-integration/ios/ios-app-clip.md @@ -38,13 +38,13 @@ the project settings. Press **+** at the bottom of the target list to add a new target. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/add-target.png" %} + **2.2** Select the **App Clip** type for your new target. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/add-app-clip.png" %} + **2.3** @@ -58,21 +58,21 @@ Select the same language as your original target for **Language**. don't create a Swift App Clip target for an Objective-C main target, and vice versa.) -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/app-clip-details.png" %} + **2.4** In the following dialog, activate the new scheme for the new target. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/activate-scheme.png" %} + **2.5** Back in the project settings, open the **Build Phases** tab. Drag **Embedded App Clips** to above **Thin Binary**. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/embedded-app-clips.png" %} + ## Step 3 - Remove unneeded files @@ -90,7 +90,7 @@ how much of this template to keep to invoke from this code later. ::: -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/clean-files.png" %} + Move files to trash. @@ -103,7 +103,7 @@ Open the `Info.plist` file in the App Clip group. Delete the entire dictionary entry for **Application Scene Manifest**. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/scene-manifest.png" %} + ## Step 4 - Share build configurations @@ -130,7 +130,7 @@ required build settings. Set **iOS Deployment Target** to at least **16.0** to take advantage of the 15MB size limit. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/configuration.png" %} + **4.2** @@ -154,7 +154,7 @@ select the file, then in the first tab of the inspector, also include the App Clip target in the `Target Membership` checkbox group. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/add-target-membership.png" %} + ### Option 2 - Customize Flutter launch for App Clip @@ -180,7 +180,7 @@ Open the `.entitlements` file. Add an `Associated Domains` Array type. Add a row to the array with `appclips:`. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/app-clip-entitlements.png" %} + **6.2** @@ -197,7 +197,7 @@ Open the file and delete the entry for the main app's entitlement file (leave that entry for the App Clip's entitlement file). -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/main-app-entitlements.png" %} + **6.3** @@ -207,7 +207,7 @@ Set the **Code Signing Entitlements** setting to the relative path of the second entitlements file created for the main app. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/main-app-entitlements-setting.png" %} + ## Step 7 - Integrate Flutter @@ -222,14 +222,14 @@ build setting to `Runner/Runner-Bridging-Header.h` In other words, the same as the main app target's build settings. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/bridge-header.png" %} + **7.2** Now open the **Build Phases** tab. Press the **+** sign and select **New Run Script Phase**. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/new-build-phase.png" %} + Drag that new phase to below the **Dependencies** phase. @@ -244,7 +244,7 @@ Uncheck **Based on dependency analysis**. In other words, the same as the main app target's build phases. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/xcode-backend-build.png" %} + This ensures that your Flutter Dart code is compiled when running the App Clip target. @@ -265,7 +265,7 @@ Uncheck **Based on dependency analysis**. In other words, the same as the main app target's build phases. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/xcode-backend-embed.png" %} + This ensures that your Flutter app and engine are embedded into the App Clip bundle. @@ -341,7 +341,7 @@ You can now run your App Clip target from Xcode by selecting your App Clip target from the scheme drop-down, selecting an iOS 16 or higher device and pressing run. -{% render docs/app-figure.md, image:"development/platform-integration/ios-app-clip/run-select.png" %} + To test launching an App Clip from the beginning, also consult Apple's doc on diff --git a/src/content/platform-integration/ios/platform-views.md b/src/content/platform-integration/ios/platform-views.md index 461272ff133..f18c0c913c1 100644 --- a/src/content/platform-integration/ios/platform-views.md +++ b/src/content/platform-integration/ios/platform-views.md @@ -41,7 +41,7 @@ On the Dart side, create a `Widget` and add the build implementation, as shown in the following steps. -In the Dart widget file, make changes similar to those +In the Dart widget file, make changes similar to those shown in `native_view_example.dart`:
    @@ -90,8 +90,8 @@ For more information, see the API docs for: On the platform side, use either Swift or Objective-C: -{% tabs "darwin-language" %} -{% tab "Swift" %} + + Implement the factory and the platform view. The `FLNativeViewFactory` creates the platform view, @@ -204,8 +204,8 @@ class FLPlugin: NSObject, FlutterPlugin { } ``` -{% endtab %} -{% tab "Objective-C" %} + + In Objective-C, add the headers for the factory and the platform view. For example, as shown in `FLNativeView.h`: @@ -338,8 +338,8 @@ modify the main plugin file @end ``` -{% endtab %} -{% endtabs %} + + For more information, see the API docs for: @@ -382,12 +382,12 @@ Widget build(BuildContext context) { Platform views in Flutter come with performance trade-offs. -For complex cases, there are some techniques that can be used +For complex cases, there are some techniques that can be used to mitigate performance issues. -For example, you could use a placeholder texture while an -animation is happening in Dart. -In other words, if an animation is slow while a platform view is rendered, +For example, you could use a placeholder texture while an +animation is happening in Dart. +In other words, if an animation is slow while a platform view is rendered, then consider taking a screenshot of the native view and rendering it as a texture. @@ -397,7 +397,7 @@ There are some limitations when composing iOS Platform Views. - The [`ShaderMask`][] and [`ColorFiltered`][] widgets are not supported. - The [`BackdropFilter`][] widget is supported, - but there are some limitations on how it can be used. + but there are some limitations on how it can be used. For more details, check out the [iOS Platform View Backdrop Filter Blur design doc][design-doc]. diff --git a/src/content/platform-integration/ios/setup.md b/src/content/platform-integration/ios/setup.md index 2370457a0e8..c09e9f2d613 100644 --- a/src/content/platform-integration/ios/setup.md +++ b/src/content/platform-integration/ios/setup.md @@ -111,8 +111,8 @@ it's easier to get set up than a physical iOS device. However, you should also test your app on an actual physical device. -{% tabs "ios-simulator-or-physical-device" %} -{% tab "Simulator" %} + + Start the iOS Simulator with the following command: @@ -126,8 +126,8 @@ on the Apple Developer site. [Downloading and installing additional Xcode components]: {{site.apple-dev}}/documentation/xcode/downloading-and-installing-additional-xcode-components -{% endtab %} -{% tab "Physical device" %} + + :::warning An upcoming change to iOS has caused a temporary break in Flutter's debug mode @@ -151,7 +151,7 @@ Set up each iOS device on which you want to test. 1. Click **Trust**. ![Trust Mac](/assets/images/docs/setup/trust-computer.png) - + 1.

    Configure your physical iOS device

    Apple requires enabling **[Developer Mode][]** @@ -224,8 +224,8 @@ Set up each iOS device on which you want to test. [Apple Developer program]: {{site.apple-dev}}/programs/ [Apple Developer account]: {{site.apple-dev}}/account -{% endtab %} -{% endtabs %} +
    +
    --- @@ -292,4 +292,3 @@ or begin improving integration with iOS. - diff --git a/src/content/platform-integration/macos/c-interop.md b/src/content/platform-integration/macos/c-interop.md index 5dad27b4c60..743288d0d12 100644 --- a/src/content/platform-integration/macos/c-interop.md +++ b/src/content/platform-integration/macos/c-interop.md @@ -79,7 +79,7 @@ $ cd native_add :::note You can exclude platforms from `--platforms` that you don't want -to build to. However, you need to include the platform of +to build to. However, you need to include the platform of the device you are testing on. ::: @@ -261,4 +261,4 @@ the symbols are stripped by Xcode. {% endcomment %} -{% render docs/resource-links/ffi-video-resources.md, site: site %} +{% render "docs/resource-links/ffi-video-resources.md", site: site %} diff --git a/src/content/platform-integration/platform-channels.md b/src/content/platform-integration/platform-channels.md index e1dfec383da..67e27eac9c7 100644 --- a/src/content/platform-integration/platform-channels.md +++ b/src/content/platform-integration/platform-channels.md @@ -90,8 +90,8 @@ automatically when you send and receive values. The following table shows how Dart values are received on the platform side and vice versa: -{% tabs "platform-channel-language" %} -{% tab "Kotlin" %} + + | Dart | Kotlin | | ----------------- | ------------- | @@ -111,8 +111,8 @@ platform side and vice versa: {:.table .table-striped} -{% endtab %} -{% tab "Java" %} + + | Dart | Java | | ----------------- | --------------------- | @@ -132,8 +132,8 @@ platform side and vice versa: {:.table .table-striped} -{% endtab %} -{% tab "Swift" %} + + | Dart | Swift | | ----------------- | ----------------------------------------- | @@ -153,8 +153,8 @@ platform side and vice versa: {:.table .table-striped} -{% endtab %} -{% tab "Obj-C" %} + + | Dart | Objective-C | | ----------------- | ------------------------------------------------ | @@ -174,8 +174,8 @@ platform side and vice versa: {:.table .table-striped} -{% endtab %} -{% tab "C++" %} + + | Dart | C++ | | ------------------ | ---------------------------------------------------------- | @@ -195,8 +195,8 @@ platform side and vice versa: {:.table .table-striped} -{% endtab %} -{% tab "C" %} + + | Dart | C (GObject) | | ------------------ | --------------------------- | @@ -215,8 +215,8 @@ platform side and vice versa: {:.table .table-striped} -{% endtab %} -{% endtabs %} + + [MessageCodec]: https://api.flutter.dev/flutter/services/MessageCodec-class.html @@ -346,8 +346,8 @@ Widget build(BuildContext context) { ### Step 3: Add an Android platform-specific implementation -{% tabs "android-language" %} -{% tab "Kotlin" %} + + Start by opening the Android host portion of your Flutter app in Android Studio: @@ -458,8 +458,8 @@ And replace with the following: } ``` -{% endtab %} -{% tab "Java" %} + + Start by opening the Android host portion of your Flutter app in Android Studio: @@ -580,8 +580,8 @@ And replace with the following: ); ``` -{% endtab %} -{% endtabs %} + + You should now be able to run the app on Android. If using the Android Emulator, set the battery level in the Extended Controls panel @@ -589,8 +589,8 @@ accessible from the **...** button in the toolbar. ### Step 4: Add an iOS platform-specific implementation -{% tabs "darwin-language" %} -{% tab "Swift" %} + + Start by opening the iOS host portion of your Flutter app in Xcode: @@ -673,8 +673,8 @@ batteryChannel.setMethodCallHandler({ }) ``` -{% endtab %} -{% tab "Objective-C" %} + + Start by opening the iOS host portion of the Flutter app in Xcode: @@ -762,8 +762,8 @@ __weak typeof(self) weakSelf = self; }]; ``` -{% endtab %} -{% endtabs %} + + You should now be able to run the app on iOS. If using the iOS Simulator, @@ -1235,9 +1235,9 @@ In order for a channel's platform side handler to execute on a background thread on an Android app, you must use the Task Queue API. -{% tabs "lang-tabs" %} + -{% tab "Kotlin" %} + ```kotlin override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { @@ -1251,9 +1251,9 @@ override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.Flu } ``` -{% endtab %} + -{% tab "Java" %} + ```java @Override @@ -1271,9 +1271,9 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { } ``` -{% endtab %} + -{% endtabs %} + ### Execute channel handlers on a background thread (iOS) @@ -1281,9 +1281,9 @@ In order for a channel's platform side handler to execute on a background thread on an iOS app, you must use the Task Queue API. -{% tabs "lang-tabs" %} + -{% tab "Swift" %} + ```swift public static func register(with registrar: FlutterPluginRegistrar) { @@ -1297,9 +1297,9 @@ public static func register(with registrar: FlutterPluginRegistrar) { } ``` -{% endtab %} + -{% tab "Objective-C" %} + ```objc + (void)registerWithRegistrar:(NSObject*)registrar { @@ -1315,9 +1315,9 @@ public static func register(with registrar: FlutterPluginRegistrar) { } ``` -{% endtab %} + -{% endtabs %} + ### Jump to the UI thread (Android) {: #jumping-to-the-ui-thread-in-android } @@ -1329,9 +1329,9 @@ In Android, you can accomplish this by `post()`ing a which causes the `Runnable` to execute on the main thread at the next opportunity. -{% tabs "lang-tabs" %} + -{% tab "Kotlin" %} + ```kotlin Handler(Looper.getMainLooper()).post { @@ -1339,9 +1339,9 @@ Handler(Looper.getMainLooper()).post { } ``` -{% endtab %} + -{% tab "Java" %} + ```java new Handler(Looper.getMainLooper()).post(new Runnable() { @@ -1352,9 +1352,9 @@ new Handler(Looper.getMainLooper()).post(new Runnable() { }); ``` -{% endtab %} + -{% endtabs %} + ### Jump to the main thread (iOS) {: #jumping-to-the-main-thread-in-ios } @@ -1364,9 +1364,9 @@ iOS's main thread to execute a channel method. You can accomplish this in iOS by executing a [block][] on the main [dispatch queue][]: -{% tabs "lang-tabs" %} + -{% tab "Objective-C" %} + ```objc dispatch_async(dispatch_get_main_queue(), ^{ @@ -1374,9 +1374,9 @@ dispatch_async(dispatch_get_main_queue(), ^{ }); ``` -{% endtab %} + -{% tab "Swift" %} + ```swift DispatchQueue.main.async { @@ -1384,9 +1384,9 @@ DispatchQueue.main.async { } ``` -{% endtab %} + -{% endtabs %} + ## Supplementals diff --git a/src/content/platform-integration/web/index.md b/src/content/platform-integration/web/index.md index 1cc80de79d1..915f005491d 100644 --- a/src/content/platform-integration/web/index.md +++ b/src/content/platform-integration/web/index.md @@ -21,7 +21,7 @@ a binary instruction format that enables fast apps on all major browsers. For a glimpse into the benefits of using WebAssembly, check out the following video. -{% ytEmbed 'lpnKWK-KEYs?start=1712', 'What\'s new in Flutter - WebAssembly' %} + ## How it works diff --git a/src/content/platform-integration/web/web-dev-config-file.md b/src/content/platform-integration/web/web-dev-config-file.md index e4051484caa..5b560b28ee8 100644 --- a/src/content/platform-integration/web/web-dev-config-file.md +++ b/src/content/platform-integration/web/web-dev-config-file.md @@ -1,6 +1,6 @@ --- title: Set up a web development configuration file -short-title: Web development configuration +shortTitle: Web development configuration description: >- Centralize web development settings including a development proxy --- diff --git a/src/content/reference/crash-reporting.md b/src/content/reference/crash-reporting.md index 2aa73ba9eeb..647bac581ce 100644 --- a/src/content/reference/crash-reporting.md +++ b/src/content/reference/crash-reporting.md @@ -2,6 +2,7 @@ title: Flutter crash reporting description: >- How Google uses crash reporting, what is collected, and how to opt out. +showBreadcrumbs: false --- If you have not opted-out of Flutter's analytics and crash reporting, diff --git a/src/content/reference/create-new-app.md b/src/content/reference/create-new-app.md index a8b19290780..0e70d5b165d 100644 --- a/src/content/reference/create-new-app.md +++ b/src/content/reference/create-new-app.md @@ -4,6 +4,7 @@ shortTitle: Create a new app description: >- Learn how to bootstrap a new Flutter application from your command-line, different editors, and even in the cloud. +showBreadcrumbs: false --- This page provides step-by-step instructions on how to diff --git a/src/content/reference/flutter-cli.md b/src/content/reference/flutter-cli.md index f33ca71b10d..47eb1432a89 100644 --- a/src/content/reference/flutter-cli.md +++ b/src/content/reference/flutter-cli.md @@ -1,6 +1,7 @@ --- title: "flutter: The Flutter command-line tool" description: "The reference page for using 'flutter' in a terminal window." +showBreadcrumbs: false --- The `flutter` command-line tool is how developers (or IDEs on behalf of diff --git a/src/content/reference/index.md b/src/content/reference/index.md index 0f7c23ba51d..f7c66f435b2 100644 --- a/src/content/reference/index.md +++ b/src/content/reference/index.md @@ -3,4 +3,5 @@ layout: toc title: Flutter reference docs shortTitle: Reference description: Miscellaneous reference docs relating to Flutter. +showBreadcrumbs: false --- diff --git a/src/content/reference/learning-resources.md b/src/content/reference/learning-resources.md index f9fde61c974..f3826a95b9a 100644 --- a/src/content/reference/learning-resources.md +++ b/src/content/reference/learning-resources.md @@ -3,9 +3,8 @@ title: Flutter learning resources description: A catalog of Flutter sample applications, codelabs, and tutorials. shortTitle: Learning resources showBreadcrumbs: false -extraBodyClass: wide-site-content +bodyClass: wide-site-content showToc: false -js: [ { url: '/assets/js/learning-resources-index.js', defer: true } ] --- :::secondary @@ -16,37 +15,4 @@ This page lists all of our additional learning resources: * Feature-rich demo applications that show how larger applications are built. ::: -{% assign resources = learning-resources-index.codelabs | concat: learning-resources-index.cookbook | concat: learning-resources-index.demos | concat: learning-resources-index.quickstarts_flutter | concat: learning-resources-index.quickstarts_dart -%} - -{% assign filters = learning-resources-index.filters -%} - -
    -
    -
    -
    - - {% comment -%}This dropdown is shown on narrow screens{% endcomment -%} - -
    -
    - - -
    -
    - {%- render docs/learning-resources-index/grid.md resources:resources -%} -
    -
    - {%- render docs/learning-resources-index/side-filters.liquid filters:filters id:"resource-filter-group" -%} -
    -
    + diff --git a/src/content/reference/reference.json b/src/content/reference/reference.json deleted file mode 100644 index b18625462fc..00000000000 --- a/src/content/reference/reference.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "showBreadcrumbs": false -} diff --git a/src/content/reference/security-false-positives.md b/src/content/reference/security-false-positives.md index 37893c390cf..02c11de6350 100644 --- a/src/content/reference/security-false-positives.md +++ b/src/content/reference/security-false-positives.md @@ -1,6 +1,9 @@ --- title: Security false positives -description: Security vulnerabilities incorrectly reported by automated static analysis tools +description: >- + Security vulnerabilities incorrectly reported by + automated static analysis tools. +showBreadcrumbs: false --- ## Introduction diff --git a/src/content/reference/supported-platforms.md b/src/content/reference/supported-platforms.md index f85253ee532..0213024c026 100644 --- a/src/content/reference/supported-platforms.md +++ b/src/content/reference/supported-platforms.md @@ -2,6 +2,7 @@ title: Supported deployment platforms shortTitle: Supported platforms description: The platforms that Flutter supports by platform version. +showBreadcrumbs: false --- As of Flutter {{site.currentFlutterVersion}}, diff --git a/src/content/reference/user-surveys.md b/src/content/reference/user-surveys.md index 4d8fcaf7a99..135744a71c7 100644 --- a/src/content/reference/user-surveys.md +++ b/src/content/reference/user-surveys.md @@ -1,9 +1,12 @@ --- title: User surveys -description: Why users see a survey announcement, how the data is used, and how to disable. +description: >- + Why users see a survey announcement, how the data is used, and how to disable. +showBreadcrumbs: false --- ## Why do I see a survey announcement? + If you have not opted-out of Flutter's [analytics and crash reporting](/reference/crash-reporting), you may receive a survey announcement in your IDE. diff --git a/src/content/reference/widgets.md b/src/content/reference/widgets.md index 414d51e7534..82d8a91f383 100644 --- a/src/content/reference/widgets.md +++ b/src/content/reference/widgets.md @@ -5,8 +5,6 @@ shortTitle: Widgets showBreadcrumbs: false --- -{% assign sorted = catalog.widgets | sort:'name' -%} - This is an alphabetical list of many of the widgets that are bundled with Flutter. You can also [browse widgets by category][catalog]. @@ -16,12 +14,12 @@ on the [Flutter YouTube channel]({{site.social.youtube}}). Each short episode features a different Flutter widget. For more video series, see our [videos](/resources/videos) page. -{% ytEmbed 'b_sQ9bMltGU', 'Introducing the Flutter Widget of the Week' %} + [Widget of the Week playlist]({{site.yt.playlist}}PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG)
    -{% for comp in sorted -%} +{% for comp in catalog.widgets | sortBy: 'name' -%}
    {% if comp.vector -%} diff --git a/src/content/release/archive-whats-new.md b/src/content/release/archive-whats-new.md index 94c66018f4d..e8c45867fec 100644 --- a/src/content/release/archive-whats-new.md +++ b/src/content/release/archive-whats-new.md @@ -919,7 +919,7 @@ For more information, see and [What's new in Flutter 2.10][], free articles on Medium. -{% ytEmbed 'g-0B_Vfc9qM', 'Flutter Update: Windows' %} + [Announcing Flutter for Windows]: {{site.flutter-medium}}/announcing-flutter-for-windows-6979d0d01fed [What's new in Flutter 2.10]: {{site.flutter-medium}}/whats-new-in-flutter-2-10-5aafb0314b12 diff --git a/src/content/release/breaking-changes/actions-api-revision.md b/src/content/release/breaking-changes/actions-api-revision.md index a26f21bdad2..d37eb830023 100644 --- a/src/content/release/breaking-changes/actions-api-revision.md +++ b/src/content/release/breaking-changes/actions-api-revision.md @@ -4,7 +4,7 @@ description: > Removes need for FocusNode in invocations, map Intent types to Actions. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/add-applifecyclestate-hidden.md b/src/content/release/breaking-changes/add-applifecyclestate-hidden.md index af718d45f6c..438f01251d3 100644 --- a/src/content/release/breaking-changes/add-applifecyclestate-hidden.md +++ b/src/content/release/breaking-changes/add-applifecyclestate-hidden.md @@ -3,7 +3,7 @@ title: Migration guide for adding AppLifecycleState.hidden description: AppLifecycleState had an additional hidden state added. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/add-currentAutofillScope-to-TextInputClient.md b/src/content/release/breaking-changes/add-currentAutofillScope-to-TextInputClient.md index 6afd2637faa..b558ad33fdf 100644 --- a/src/content/release/breaking-changes/add-currentAutofillScope-to-TextInputClient.md +++ b/src/content/release/breaking-changes/add-currentAutofillScope-to-TextInputClient.md @@ -5,7 +5,7 @@ description: > added to the TextInputClient interface for autofill support. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/add-showAutocorrectionPromptRect.md b/src/content/release/breaking-changes/add-showAutocorrectionPromptRect.md index 6d2f70ec646..7da8b9c8431 100644 --- a/src/content/release/breaking-changes/add-showAutocorrectionPromptRect.md +++ b/src/content/release/breaking-changes/add-showAutocorrectionPromptRect.md @@ -5,7 +5,7 @@ description: > was added to the TextInputClient interface --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/android-14-nonlinear-text-scaling-migration.md b/src/content/release/breaking-changes/android-14-nonlinear-text-scaling-migration.md index 9fe616d82a4..7befe71510e 100644 --- a/src/content/release/breaking-changes/android-14-nonlinear-text-scaling-migration.md +++ b/src/content/release/breaking-changes/android-14-nonlinear-text-scaling-migration.md @@ -5,7 +5,7 @@ description: >- enabled in Flutter after v3.14. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/android-activity-control-surface-attach.md b/src/content/release/breaking-changes/android-activity-control-surface-attach.md index 52f79e34825..ff1e5ec742b 100644 --- a/src/content/release/breaking-changes/android-activity-control-surface-attach.md +++ b/src/content/release/breaking-changes/android-activity-control-surface-attach.md @@ -5,7 +5,7 @@ description: > ExclusiveAppComponent instead of Activity. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/android-java-gradle-migration-guide.md b/src/content/release/breaking-changes/android-java-gradle-migration-guide.md index 351bab73924..68de3c05a2e 100644 --- a/src/content/release/breaking-changes/android-java-gradle-migration-guide.md +++ b/src/content/release/breaking-changes/android-java-gradle-migration-guide.md @@ -5,7 +5,7 @@ description: > a run or build error from Gradle. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/android-kitkat-deprecation.md b/src/content/release/breaking-changes/android-kitkat-deprecation.md index 47d4cc41801..6a012e4d5ba 100644 --- a/src/content/release/breaking-changes/android-kitkat-deprecation.md +++ b/src/content/release/breaking-changes/android-kitkat-deprecation.md @@ -5,7 +5,7 @@ description: >- KitKat (API 19) to Lollipop (API 21). --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/android-predictive-back.md b/src/content/release/breaking-changes/android-predictive-back.md index 992f6ef1567..884363bb4f6 100644 --- a/src/content/release/breaking-changes/android-predictive-back.md +++ b/src/content/release/breaking-changes/android-predictive-back.md @@ -6,7 +6,7 @@ description: >- support Android 14's Predictive Back feature. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/android-setIsRunningInRobolectricTest-removed.md b/src/content/release/breaking-changes/android-setIsRunningInRobolectricTest-removed.md index 7b11b9b6ac7..3312d6bac6b 100644 --- a/src/content/release/breaking-changes/android-setIsRunningInRobolectricTest-removed.md +++ b/src/content/release/breaking-changes/android-setIsRunningInRobolectricTest-removed.md @@ -5,7 +5,7 @@ description: > Android engine is consolidated into the FlutterInjector. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/android-surface-plugins.md b/src/content/release/breaking-changes/android-surface-plugins.md index d7c0658b0be..e9435af0a41 100644 --- a/src/content/release/breaking-changes/android-surface-plugins.md +++ b/src/content/release/breaking-changes/android-surface-plugins.md @@ -6,7 +6,7 @@ description: >- For Impeller, use of this API is recommended. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/android-v1-embedding-create-deprecation.md b/src/content/release/breaking-changes/android-v1-embedding-create-deprecation.md index dabf2246e09..c8b08c1b2b0 100644 --- a/src/content/release/breaking-changes/android-v1-embedding-create-deprecation.md +++ b/src/content/release/breaking-changes/android-v1-embedding-create-deprecation.md @@ -3,7 +3,7 @@ title: Android v1 embedding app and plugin creation deprecation description: Gradual deprecation of the Android v1 embedding. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/androidx-migration.md b/src/content/release/breaking-changes/androidx-migration.md index 2c9cdf578da..5cf3be345c4 100644 --- a/src/content/release/breaking-changes/androidx-migration.md +++ b/src/content/release/breaking-changes/androidx-migration.md @@ -3,7 +3,7 @@ title: AndroidX migration description: How to migrate existing Flutter projects to AndroidX. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} :::note You might be directed to this page if Flutter detects diff --git a/src/content/release/breaking-changes/animation-sheet-builder-display.md b/src/content/release/breaking-changes/animation-sheet-builder-display.md index 026cae1c51c..e12c16ee67c 100644 --- a/src/content/release/breaking-changes/animation-sheet-builder-display.md +++ b/src/content/release/breaking-changes/animation-sheet-builder-display.md @@ -5,7 +5,7 @@ description: > are deprecated in favor of collate. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/annotations-return-local-position-relative-to-object.md b/src/content/release/breaking-changes/annotations-return-local-position-relative-to-object.md index 68175b05c37..b9c2754e238 100644 --- a/src/content/release/breaking-changes/annotations-return-local-position-relative-to-object.md +++ b/src/content/release/breaking-changes/annotations-return-local-position-relative-to-object.md @@ -4,7 +4,7 @@ description: > Provide annotation searches with reliable and meaningful local positions. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/appbar-theme-color.md b/src/content/release/breaking-changes/appbar-theme-color.md index 29afd1104d9..bc63098661f 100644 --- a/src/content/release/breaking-changes/appbar-theme-color.md +++ b/src/content/release/breaking-changes/appbar-theme-color.md @@ -5,7 +5,7 @@ description: >- deprecated in favor of backgroundColor for better API consistency. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/asset-manifest-dot-json.md b/src/content/release/breaking-changes/asset-manifest-dot-json.md index 84185d83167..d39cde4b3c7 100644 --- a/src/content/release/breaking-changes/asset-manifest-dot-json.md +++ b/src/content/release/breaking-changes/asset-manifest-dot-json.md @@ -4,7 +4,7 @@ description: >- Built Flutter apps will no longer include an AssetManifest.json asset file. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/bottom-navigation-title-to-label.md b/src/content/release/breaking-changes/bottom-navigation-title-to-label.md index e665ba77a2c..ebc768659ee 100644 --- a/src/content/release/breaking-changes/bottom-navigation-title-to-label.md +++ b/src/content/release/breaking-changes/bottom-navigation-title-to-label.md @@ -5,7 +5,7 @@ description: > favor of label (a String). --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/buildtextspan-buildcontext.md b/src/content/release/breaking-changes/buildtextspan-buildcontext.md index 8b7e8e1437a..a3e680426e4 100644 --- a/src/content/release/breaking-changes/buildtextspan-buildcontext.md +++ b/src/content/release/breaking-changes/buildtextspan-buildcontext.md @@ -5,7 +5,7 @@ description: > inheritors that override buildTextSpan can access inherited widgets. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/buttons.md b/src/content/release/breaking-changes/buttons.md index 15b4fd14f99..f454d9064a7 100644 --- a/src/content/release/breaking-changes/buttons.md +++ b/src/content/release/breaking-changes/buttons.md @@ -3,7 +3,7 @@ title: New Buttons and Button themes description: The basic material button classes have been replaced. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/can-request-focus.md b/src/content/release/breaking-changes/can-request-focus.md index f4d19e7bc0a..66471b8cfc6 100644 --- a/src/content/release/breaking-changes/can-request-focus.md +++ b/src/content/release/breaking-changes/can-request-focus.md @@ -5,7 +5,7 @@ description: >- canRequestFocus parameter of its FocusNode. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/checkbox-fillColor.md b/src/content/release/breaking-changes/checkbox-fillColor.md index 49c6bbe0f21..e75662757ff 100644 --- a/src/content/release/breaking-changes/checkbox-fillColor.md +++ b/src/content/release/breaking-changes/checkbox-fillColor.md @@ -5,7 +5,7 @@ description: > background when the checkbox is unselected. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/chip-usedeletebuttontooltip-migration.md b/src/content/release/breaking-changes/chip-usedeletebuttontooltip-migration.md index 928a1c591d3..e83968c059f 100644 --- a/src/content/release/breaking-changes/chip-usedeletebuttontooltip-migration.md +++ b/src/content/release/breaking-changes/chip-usedeletebuttontooltip-migration.md @@ -5,7 +5,7 @@ description: > a delete button in favor of deleteButtonTooltipMessage. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/clip-behavior.md b/src/content/release/breaking-changes/clip-behavior.md index 36aca20f4f1..9fe0c83542b 100644 --- a/src/content/release/breaking-changes/clip-behavior.md +++ b/src/content/release/breaking-changes/clip-behavior.md @@ -4,7 +4,7 @@ description: > Flutter unifies clipBehavior and defaults to not clip in most cases. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/clipboard-data-required.md b/src/content/release/breaking-changes/clipboard-data-required.md index 0f5bf1c341d..447ff3a8148 100644 --- a/src/content/release/breaking-changes/clipboard-data-required.md +++ b/src/content/release/breaking-changes/clipboard-data-required.md @@ -5,7 +5,7 @@ description: > at least one clipboard data variant must be provided. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/component-theme-normalization-updates.md b/src/content/release/breaking-changes/component-theme-normalization-updates.md index be19ab45d30..8d2356c1f36 100644 --- a/src/content/release/breaking-changes/component-theme-normalization-updates.md +++ b/src/content/release/breaking-changes/component-theme-normalization-updates.md @@ -6,7 +6,7 @@ description: >- Material library. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/component-theme-normalization.md b/src/content/release/breaking-changes/component-theme-normalization.md index 708c8b5066a..6b4aa5aa26d 100644 --- a/src/content/release/breaking-changes/component-theme-normalization.md +++ b/src/content/release/breaking-changes/component-theme-normalization.md @@ -5,7 +5,7 @@ description: >- Flutter's convention for component themes in the Material library. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/container-color.md b/src/content/release/breaking-changes/container-color.md index b52287ccec3..1574c7261d2 100644 --- a/src/content/release/breaking-changes/container-color.md +++ b/src/content/release/breaking-changes/container-color.md @@ -5,7 +5,7 @@ description: > no longer builds the same child widgets. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/context-menus.md b/src/content/release/breaking-changes/context-menus.md index 3ac964bbd18..444fe10839b 100644 --- a/src/content/release/breaking-changes/context-menus.md +++ b/src/content/release/breaking-changes/context-menus.md @@ -5,7 +5,7 @@ description: > now been replaced by a generic widget builder. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/cupertino-icons-1.0.0.md b/src/content/release/breaking-changes/cupertino-icons-1.0.0.md index 1ba347aa845..099331b897e 100644 --- a/src/content/release/breaking-changes/cupertino-icons-1.0.0.md +++ b/src/content/release/breaking-changes/cupertino-icons-1.0.0.md @@ -5,7 +5,7 @@ description: > automapped to the new glyphs. Consider double-checking visually. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/cupertino-tab-bar-localizations.md b/src/content/release/breaking-changes/cupertino-tab-bar-localizations.md index d8b8746033a..0558361eab0 100644 --- a/src/content/release/breaking-changes/cupertino-tab-bar-localizations.md +++ b/src/content/release/breaking-changes/cupertino-tab-bar-localizations.md @@ -5,7 +5,7 @@ description: > CupertinoTabBar requires a Localizations parent. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/deep-links-flag-change.md b/src/content/release/breaking-changes/deep-links-flag-change.md index 5f16821384b..11a6c3f9665 100644 --- a/src/content/release/breaking-changes/deep-links-flag-change.md +++ b/src/content/release/breaking-changes/deep-links-flag-change.md @@ -5,7 +5,7 @@ description: >- set Flutter's deep linking flag to false. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/default-abi-filters-android.md b/src/content/release/breaking-changes/default-abi-filters-android.md index 85066171e02..7898381fe52 100644 --- a/src/content/release/breaking-changes/default-abi-filters-android.md +++ b/src/content/release/breaking-changes/default-abi-filters-android.md @@ -5,7 +5,7 @@ description: >- for Android builds, which might break custom abiFilters settings. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/default-desktop-scrollbars.md b/src/content/release/breaking-changes/default-desktop-scrollbars.md index 5ff6074da77..2057600536b 100644 --- a/src/content/release/breaking-changes/default-desktop-scrollbars.md +++ b/src/content/release/breaking-changes/default-desktop-scrollbars.md @@ -4,7 +4,7 @@ description: > ScrollBehaviors will now automatically build Scrollbars on Desktop platforms. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/default-scroll-behavior-drag.md b/src/content/release/breaking-changes/default-scroll-behavior-drag.md index 0f4ddb73814..fd7429c26b9 100644 --- a/src/content/release/breaking-changes/default-scroll-behavior-drag.md +++ b/src/content/release/breaking-changes/default-scroll-behavior-drag.md @@ -5,7 +5,7 @@ description: > PointerDeviceKinds can drag Scrollables. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/default-systemuimode-edge-to-edge.md b/src/content/release/breaking-changes/default-systemuimode-edge-to-edge.md index 139fc65984c..727a5a98215 100644 --- a/src/content/release/breaking-changes/default-systemuimode-edge-to-edge.md +++ b/src/content/release/breaking-changes/default-systemuimode-edge-to-edge.md @@ -5,7 +5,7 @@ description: >- in to edge-to-edge mode. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} :::note You might have found this page because you see a warning in the Google Play diff --git a/src/content/release/breaking-changes/deprecate-buttonbar.md b/src/content/release/breaking-changes/deprecate-buttonbar.md index 083c40e19de..f3b7790ba3a 100644 --- a/src/content/release/breaking-changes/deprecate-buttonbar.md +++ b/src/content/release/breaking-changes/deprecate-buttonbar.md @@ -5,7 +5,7 @@ description: >- a more efficient widget, OverflowBar. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/deprecate-dropdownbuttonformfield-value.md b/src/content/release/breaking-changes/deprecate-dropdownbuttonformfield-value.md index bd25ced841c..ad7c340cc7c 100644 --- a/src/content/release/breaking-changes/deprecate-dropdownbuttonformfield-value.md +++ b/src/content/release/breaking-changes/deprecate-dropdownbuttonformfield-value.md @@ -7,7 +7,7 @@ description: >- replaced by the parameter `initialValue`. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/deprecate-focusable.md b/src/content/release/breaking-changes/deprecate-focusable.md index 3f4a9754130..57918502e77 100644 --- a/src/content/release/breaking-changes/deprecate-focusable.md +++ b/src/content/release/breaking-changes/deprecate-focusable.md @@ -4,7 +4,7 @@ description: > The `focusable` parameter has been replaced by `isFocused`. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/deprecate-inputdecoration-maintainhintheight.md b/src/content/release/breaking-changes/deprecate-inputdecoration-maintainhintheight.md index b34689fd62d..99f01cac4d4 100644 --- a/src/content/release/breaking-changes/deprecate-inputdecoration-maintainhintheight.md +++ b/src/content/release/breaking-changes/deprecate-inputdecoration-maintainhintheight.md @@ -6,7 +6,7 @@ description: >- `InputDecoration.maintainHintSize`. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/deprecate-overlay-portal-targets-root.md b/src/content/release/breaking-changes/deprecate-overlay-portal-targets-root.md index af236d1efaa..924b541de70 100644 --- a/src/content/release/breaking-changes/deprecate-overlay-portal-targets-root.md +++ b/src/content/release/breaking-changes/deprecate-overlay-portal-targets-root.md @@ -4,7 +4,7 @@ description: >- Learn about changes to the OverlayPortal in Flutter. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/deprecate-textscalefactor.md b/src/content/release/breaking-changes/deprecate-textscalefactor.md index 28926f87de4..09b5694cc40 100644 --- a/src/content/release/breaking-changes/deprecate-textscalefactor.md +++ b/src/content/release/breaking-changes/deprecate-textscalefactor.md @@ -5,7 +5,7 @@ description: >- preparation for Android 14 nonlinear text scaling support. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/deprecate-themedata-dialogbackgroundcolor.md b/src/content/release/breaking-changes/deprecate-themedata-dialogbackgroundcolor.md index 813f0f0a145..397bc127e42 100644 --- a/src/content/release/breaking-changes/deprecate-themedata-dialogbackgroundcolor.md +++ b/src/content/release/breaking-changes/deprecate-themedata-dialogbackgroundcolor.md @@ -6,7 +6,7 @@ description: >- `DialogThemeData.backgroundColor`. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/deprecate-themedata-indicatorcolor.md b/src/content/release/breaking-changes/deprecate-themedata-indicatorcolor.md index 8e3ab8831b6..9bb1bc0b93a 100644 --- a/src/content/release/breaking-changes/deprecate-themedata-indicatorcolor.md +++ b/src/content/release/breaking-changes/deprecate-themedata-indicatorcolor.md @@ -6,7 +6,7 @@ description: >- `TabBarThemeData.indicatorColor`. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/describe-enum.md b/src/content/release/breaking-changes/describe-enum.md index 725b01e7079..8da24ea0a93 100644 --- a/src/content/release/breaking-changes/describe-enum.md +++ b/src/content/release/breaking-changes/describe-enum.md @@ -3,7 +3,7 @@ title: Migration guide for describeEnum and EnumProperty description: Learn about the removal of describeEnum and how to migrate. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/dialog-border-radius.md b/src/content/release/breaking-changes/dialog-border-radius.md index 3f9492532c3..03f03d0cab0 100644 --- a/src/content/release/breaking-changes/dialog-border-radius.md +++ b/src/content/release/breaking-changes/dialog-border-radius.md @@ -3,7 +3,7 @@ title: Dialogs' Default BorderRadius description: The default BorderRadius of Dialog widgets is changing. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/dispose.md b/src/content/release/breaking-changes/dispose.md index d6100895240..bc63ae5ba66 100644 --- a/src/content/release/breaking-changes/dispose.md +++ b/src/content/release/breaking-changes/dispose.md @@ -4,7 +4,7 @@ description: > 'dispose()' might fail because of double disposal. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/editable-text-focus-attachment.md b/src/content/release/breaking-changes/editable-text-focus-attachment.md index 6970db6447a..9053a821535 100644 --- a/src/content/release/breaking-changes/editable-text-focus-attachment.md +++ b/src/content/release/breaking-changes/editable-text-focus-attachment.md @@ -5,7 +5,7 @@ description: > EditableTextState's BuildContext. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/editable-text-scroll-into-view.md b/src/content/release/breaking-changes/editable-text-scroll-into-view.md index 4608c7c8533..a6a35658a49 100644 --- a/src/content/release/breaking-changes/editable-text-scroll-into-view.md +++ b/src/content/release/breaking-changes/editable-text-scroll-into-view.md @@ -5,7 +5,7 @@ description: > use the current selection extent. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/eliminating-nullok-parameters.md b/src/content/release/breaking-changes/eliminating-nullok-parameters.md index 004193925d9..8e3c0ce88d5 100644 --- a/src/content/release/breaking-changes/eliminating-nullok-parameters.md +++ b/src/content/release/breaking-changes/eliminating-nullok-parameters.md @@ -5,7 +5,7 @@ description: > API sanity in the face of null safety. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/enterText-trailing-caret.md b/src/content/release/breaking-changes/enterText-trailing-caret.md index 26428d58657..3cba7a8354b 100644 --- a/src/content/release/breaking-changes/enterText-trailing-caret.md +++ b/src/content/release/breaking-changes/enterText-trailing-caret.md @@ -5,7 +5,7 @@ description: > move the caret to the end of the input text. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/expansion-tile-controller.md b/src/content/release/breaking-changes/expansion-tile-controller.md index be266be76a8..83e9d71b537 100644 --- a/src/content/release/breaking-changes/expansion-tile-controller.md +++ b/src/content/release/breaking-changes/expansion-tile-controller.md @@ -5,7 +5,7 @@ description: > `ExpansibleController`. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/fab-theme-data-accent-properties.md b/src/content/release/breaking-changes/fab-theme-data-accent-properties.md index 7eec38ab289..cc0a40b9f5d 100644 --- a/src/content/release/breaking-changes/fab-theme-data-accent-properties.md +++ b/src/content/release/breaking-changes/fab-theme-data-accent-properties.md @@ -6,7 +6,7 @@ description: > its unnecessary use of accentIconTheme. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/flutter-driver-migration.md b/src/content/release/breaking-changes/flutter-driver-migration.md index 6a10fc904c3..7af64b5a9e1 100644 --- a/src/content/release/breaking-changes/flutter-driver-migration.md +++ b/src/content/release/breaking-changes/flutter-driver-migration.md @@ -4,7 +4,7 @@ description: >- Learn how to migrate existing flutter_driver tests to integration_test. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} diff --git a/src/content/release/breaking-changes/flutter-generate-i10n-source.md b/src/content/release/breaking-changes/flutter-generate-i10n-source.md index d205c9ada76..4f2bcf3187d 100755 --- a/src/content/release/breaking-changes/flutter-generate-i10n-source.md +++ b/src/content/release/breaking-changes/flutter-generate-i10n-source.md @@ -6,7 +6,7 @@ description: >- directory, and not the synthetic package `package:flutter_gen`. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/flutter-gradle-plugin-apply.md b/src/content/release/breaking-changes/flutter-gradle-plugin-apply.md index 49bbdfe44cb..3c6097386b6 100644 --- a/src/content/release/breaking-changes/flutter-gradle-plugin-apply.md +++ b/src/content/release/breaking-changes/flutter-gradle-plugin-apply.md @@ -5,7 +5,7 @@ description: >- new, declarative format. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/flutter-lints-package.md b/src/content/release/breaking-changes/flutter-lints-package.md index 1e0405f0039..6127bdcb815 100644 --- a/src/content/release/breaking-changes/flutter-lints-package.md +++ b/src/content/release/breaking-changes/flutter-lints-package.md @@ -5,7 +5,7 @@ description: > recommended lints, which encourage good coding practices. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/flutter-memory-allocations.md b/src/content/release/breaking-changes/flutter-memory-allocations.md index c12470f59d2..6f8b8918625 100644 --- a/src/content/release/breaking-changes/flutter-memory-allocations.md +++ b/src/content/release/breaking-changes/flutter-memory-allocations.md @@ -4,7 +4,7 @@ description: >- MemoryAllocations is renamed to FlutterMemoryAllocations. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/flutter-plugins-configuration.md b/src/content/release/breaking-changes/flutter-plugins-configuration.md index b88d20e95bf..5d993fb378f 100644 --- a/src/content/release/breaking-changes/flutter-plugins-configuration.md +++ b/src/content/release/breaking-changes/flutter-plugins-configuration.md @@ -6,7 +6,7 @@ description: >- must also be updated. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/flutter-root-version-file.md b/src/content/release/breaking-changes/flutter-root-version-file.md index dad061489cf..b00991195e6 100644 --- a/src/content/release/breaking-changes/flutter-root-version-file.md +++ b/src/content/release/breaking-changes/flutter-root-version-file.md @@ -6,7 +6,7 @@ description: >- references to it must also be updated. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/forgetchild-call-super.md b/src/content/release/breaking-changes/forgetchild-call-super.md index e5e4984682e..916e1f6564c 100644 --- a/src/content/release/breaking-changes/forgetchild-call-super.md +++ b/src/content/release/breaking-changes/forgetchild-call-super.md @@ -4,7 +4,7 @@ description: > Any element subclasses that override forgetChild are required to call super. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/form-field-autovalidation-api.md b/src/content/release/breaking-changes/form-field-autovalidation-api.md index ef250123e0c..c1afe9d6f5b 100644 --- a/src/content/release/breaking-changes/form-field-autovalidation-api.md +++ b/src/content/release/breaking-changes/form-field-autovalidation-api.md @@ -3,7 +3,7 @@ title: The new Form, FormField auto-validation API description: Gives more control in how to auto validate a Form and a FormField. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/form-semantics.md b/src/content/release/breaking-changes/form-semantics.md index b42e1120861..b15b0dde66c 100644 --- a/src/content/release/breaking-changes/form-semantics.md +++ b/src/content/release/breaking-changes/form-semantics.md @@ -5,7 +5,7 @@ description: >- which prevents it from being used directly as a sliver. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/gesture-recognizer-add-allowed-pointer.md b/src/content/release/breaking-changes/gesture-recognizer-add-allowed-pointer.md index 6b740c9042e..abc7629a9e8 100644 --- a/src/content/release/breaking-changes/gesture-recognizer-add-allowed-pointer.md +++ b/src/content/release/breaking-changes/gesture-recognizer-add-allowed-pointer.md @@ -5,7 +5,7 @@ description: > override `addAllowedPointer` to take a `PointerDownEvent` --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/hero-controller-scope.md b/src/content/release/breaking-changes/hero-controller-scope.md index c648efb0a8c..5dbcb47b2f3 100644 --- a/src/content/release/breaking-changes/hero-controller-scope.md +++ b/src/content/release/breaking-changes/hero-controller-scope.md @@ -5,7 +5,7 @@ description: > one hero controller scope can only subscribe to one navigator at a time. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/ignoringsemantics-migration.md b/src/content/release/breaking-changes/ignoringsemantics-migration.md index a5d5ffc2967..8bc36e97f36 100644 --- a/src/content/release/breaking-changes/ignoringsemantics-migration.md +++ b/src/content/release/breaking-changes/ignoringsemantics-migration.md @@ -3,7 +3,7 @@ title: Migration guide for ignoringSemantics in IgnorePointer and related classe description: Removal of ignoringSemantics in IgnorePointer and related classes. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/image-cache-and-provider.md b/src/content/release/breaking-changes/image-cache-and-provider.md index 18f3c59854f..c43b8088378 100644 --- a/src/content/release/breaking-changes/image-cache-and-provider.md +++ b/src/content/release/breaking-changes/image-cache-and-provider.md @@ -5,7 +5,7 @@ description: > ImageProvider has marked resolve as @nonVirtual. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/image-filter-blur-tilemode.md b/src/content/release/breaking-changes/image-filter-blur-tilemode.md index 6788792c84d..8165496bb0e 100644 --- a/src/content/release/breaking-changes/image-filter-blur-tilemode.md +++ b/src/content/release/breaking-changes/image-filter-blur-tilemode.md @@ -5,7 +5,7 @@ description: >- select one based on the rendering context. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/image-provider-load-buffer.md b/src/content/release/breaking-changes/image-provider-load-buffer.md index 9a48a3f5f0c..541c52bf0b6 100644 --- a/src/content/release/breaking-changes/image-provider-load-buffer.md +++ b/src/content/release/breaking-changes/image-provider-load-buffer.md @@ -5,7 +5,7 @@ description: > new loadBuffer API instead of the existing load API. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/imagecache-large-images.md b/src/content/release/breaking-changes/imagecache-large-images.md index ff9035fcb0a..dbb2098d741 100644 --- a/src/content/release/breaking-changes/imagecache-large-images.md +++ b/src/content/release/breaking-changes/imagecache-large-images.md @@ -4,7 +4,7 @@ description: > Stop increasing the ImageCache maxByteSize to accommodate large images. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/index.md b/src/content/release/breaking-changes/index.md index cd93d23ed2c..f7050f80f67 100644 --- a/src/content/release/breaking-changes/index.md +++ b/src/content/release/breaking-changes/index.md @@ -9,7 +9,7 @@ As described in the [breaking change policy][], on occasion we publish guides for migrating code across a breaking change. -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} To be notified about future breaking changes, join the groups [Flutter announce][] and [Dart announce][]. diff --git a/src/content/release/breaking-changes/input-decoration-collapsed.md b/src/content/release/breaking-changes/input-decoration-collapsed.md index 62a7b9d290b..fd04103f57b 100644 --- a/src/content/release/breaking-changes/input-decoration-collapsed.md +++ b/src/content/release/breaking-changes/input-decoration-collapsed.md @@ -6,7 +6,7 @@ description: > replacement because they have no effect. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/insert-content-text-input-client.md b/src/content/release/breaking-changes/insert-content-text-input-client.md index 65d5191a10e..cd7e97c5655 100644 --- a/src/content/release/breaking-changes/insert-content-text-input-client.md +++ b/src/content/release/breaking-changes/insert-content-text-input-client.md @@ -5,7 +5,7 @@ description: > Android virtual keyboards to insert rich content into Flutter TextFields. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/integration-test-default-golden-comparator.md b/src/content/release/breaking-changes/integration-test-default-golden-comparator.md index 72888b500c5..b5942103435 100644 --- a/src/content/release/breaking-changes/integration-test-default-golden-comparator.md +++ b/src/content/release/breaking-changes/integration-test-default-golden-comparator.md @@ -6,7 +6,7 @@ description: >- has changed, and correctly uses the host filesystem. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary @@ -54,15 +54,15 @@ In cases where users wrote custom test infrastructure and comparators, consider instead removing the [`goldenFileComparator`][] overrides, and instead rely on the (new) default which should work as expected: -```diff -import 'package:integration_test/integration_test.dart'; --import 'package:my_integration_test/custom_golden_file_comparator.dart'; +```dart diff + import 'package:integration_test/integration_test.dart'; +- import 'package:my_integration_test/custom_golden_file_comparator.dart'; -void main() { -- goldenFileComparator = CustomGoldenFileComparatorThatWorks(); + void main() { +- goldenFileComparator = CustomGoldenFileComparatorThatWorks(); - // ... -} + // ... + } ``` _Fun fact_: The existing code that was used for diff --git a/src/content/release/breaking-changes/ios-flutterviewcontroller-splashscreenview-nullable.md b/src/content/release/breaking-changes/ios-flutterviewcontroller-splashscreenview-nullable.md index 25a06e97b1e..b1af6396bd1 100644 --- a/src/content/release/breaking-changes/ios-flutterviewcontroller-splashscreenview-nullable.md +++ b/src/content/release/breaking-changes/ios-flutterviewcontroller-splashscreenview-nullable.md @@ -4,7 +4,7 @@ description: > FlutterViewController splashScreenView changed from nonnull to nullable. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/key-event-migration.md b/src/content/release/breaking-changes/key-event-migration.md index c6dc1ca5cd6..a16fc7b9ae5 100644 --- a/src/content/release/breaking-changes/key-event-migration.md +++ b/src/content/release/breaking-changes/key-event-migration.md @@ -6,7 +6,7 @@ description: >- HardwareKeyboard. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/kotlin-version.md b/src/content/release/breaking-changes/kotlin-version.md index 9994dd845b2..cb3bf538da6 100644 --- a/src/content/release/breaking-changes/kotlin-version.md +++ b/src/content/release/breaking-changes/kotlin-version.md @@ -5,7 +5,7 @@ description: > now require Kotlin 1.5.31 or greater. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} :::important As of Flutter 3.16, the default Gradle build scripts differ across diff --git a/src/content/release/breaking-changes/layout-builder-optimization.md b/src/content/release/breaking-changes/layout-builder-optimization.md index 2d1aa631f9a..2a3698bb8c9 100644 --- a/src/content/release/breaking-changes/layout-builder-optimization.md +++ b/src/content/release/breaking-changes/layout-builder-optimization.md @@ -4,7 +4,7 @@ description: > LayoutBuilder and SliverLayoutBuilder call the builder function less often. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/macos-windows-merged-threads.md b/src/content/release/breaking-changes/macos-windows-merged-threads.md index aefbcf1c572..ce5692884fd 100644 --- a/src/content/release/breaking-changes/macos-windows-merged-threads.md +++ b/src/content/release/breaking-changes/macos-windows-merged-threads.md @@ -4,7 +4,7 @@ description: >- Learn about threading changes on macOS and Windows in Flutter 3.35. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/material-3-default.md b/src/content/release/breaking-changes/material-3-default.md index a39eaa7bedb..9bd577428a0 100644 --- a/src/content/release/breaking-changes/material-3-default.md +++ b/src/content/release/breaking-changes/material-3-default.md @@ -4,7 +4,7 @@ description: >- The ThemeData.useMaterial3 flag is now set to true by default. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/material-3-migration.md b/src/content/release/breaking-changes/material-3-migration.md index 5b9a1e7b935..47d982049e8 100644 --- a/src/content/release/breaking-changes/material-3-migration.md +++ b/src/content/release/breaking-changes/material-3-migration.md @@ -4,7 +4,7 @@ description: >- Learn how to migrate your Flutter app's UI from Material 2 to Material 3. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/material-chip-button-semantics.md b/src/content/release/breaking-changes/material-chip-button-semantics.md index a6160752f99..8977731a0ea 100644 --- a/src/content/release/breaking-changes/material-chip-button-semantics.md +++ b/src/content/release/breaking-changes/material-chip-button-semantics.md @@ -3,7 +3,7 @@ title: Material Chip button semantics description: Interactive Material Chips are now semantically marked as buttons. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/material-design-3-token-update.md b/src/content/release/breaking-changes/material-design-3-token-update.md index 1240240c266..2a0849fb7d0 100644 --- a/src/content/release/breaking-changes/material-design-3-token-update.md +++ b/src/content/release/breaking-changes/material-design-3-token-update.md @@ -5,7 +5,7 @@ description: >- the Flutter Material library. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/material-localized-strings.md b/src/content/release/breaking-changes/material-localized-strings.md index 54f0b1c326b..e09d8ce8106 100644 --- a/src/content/release/breaking-changes/material-localized-strings.md +++ b/src/content/release/breaking-changes/material-localized-strings.md @@ -5,7 +5,7 @@ description: > material localizations to widgets localizations. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/material-state.md b/src/content/release/breaking-changes/material-state.md index 935a74bebd4..9a613fc941e 100644 --- a/src/content/release/breaking-changes/material-state.md +++ b/src/content/release/breaking-changes/material-state.md @@ -6,7 +6,7 @@ description: >- WidgetState. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/material-theme-system-updates.md b/src/content/release/breaking-changes/material-theme-system-updates.md index 29072faa215..99f545709a1 100644 --- a/src/content/release/breaking-changes/material-theme-system-updates.md +++ b/src/content/release/breaking-changes/material-theme-system-updates.md @@ -6,7 +6,7 @@ description: >- `ThemeData`, the type of these properties have also changed accordingly. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/menus-text-style.md b/src/content/release/breaking-changes/menus-text-style.md index 0d604721ce3..7d42e118af6 100644 --- a/src/content/release/breaking-changes/menus-text-style.md +++ b/src/content/release/breaking-changes/menus-text-style.md @@ -5,7 +5,7 @@ description: >- match the Material 3 specification. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/mock-platform-channels.md b/src/content/release/breaking-changes/mock-platform-channels.md index ba73a44ba03..f96160a1f9a 100644 --- a/src/content/release/breaking-changes/mock-platform-channels.md +++ b/src/content/release/breaking-changes/mock-platform-channels.md @@ -5,7 +5,7 @@ description: > moved from package:flutter to package:flutter_test --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/modal-router-semantics-order.md b/src/content/release/breaking-changes/modal-router-semantics-order.md index 759bbe6dbc9..da9d973f548 100644 --- a/src/content/release/breaking-changes/modal-router-semantics-order.md +++ b/src/content/release/breaking-changes/modal-router-semantics-order.md @@ -5,7 +5,7 @@ description: > traverse order than its modal barrier. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/mouse-tracker-moved-to-rendering.md b/src/content/release/breaking-changes/mouse-tracker-moved-to-rendering.md index 32e3c0866dc..fa059cf9747 100644 --- a/src/content/release/breaking-changes/mouse-tracker-moved-to-rendering.md +++ b/src/content/release/breaking-changes/mouse-tracker-moved-to-rendering.md @@ -3,7 +3,7 @@ title: MouseTracker moved to rendering description: MouseTracker and related symbols moved to the rendering package. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/mouse-tracker-no-longer-attaches-annotations.md b/src/content/release/breaking-changes/mouse-tracker-no-longer-attaches-annotations.md index e035dbffd52..a7480be9960 100644 --- a/src/content/release/breaking-changes/mouse-tracker-no-longer-attaches-annotations.md +++ b/src/content/release/breaking-changes/mouse-tracker-no-longer-attaches-annotations.md @@ -6,7 +6,7 @@ description: > all three related methods are removed. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/multi-touch-scrolling.md b/src/content/release/breaking-changes/multi-touch-scrolling.md index 74dbeb418f9..e01a4e96ccc 100644 --- a/src/content/release/breaking-changes/multi-touch-scrolling.md +++ b/src/content/release/breaking-changes/multi-touch-scrolling.md @@ -5,7 +5,7 @@ description: > multitouch gestures. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/navigator-and-page-api.md b/src/content/release/breaking-changes/navigator-and-page-api.md index 3f99c8bb253..5bd31784c90 100644 --- a/src/content/release/breaking-changes/navigator-and-page-api.md +++ b/src/content/release/breaking-changes/navigator-and-page-api.md @@ -4,7 +4,7 @@ description: >- Replace Navigator's 'onPopPage' property with the 'onDidRemovePage' property. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/navigator-complete-route.md b/src/content/release/breaking-changes/navigator-complete-route.md index 39b06da99c5..20608b492d0 100644 --- a/src/content/release/breaking-changes/navigator-complete-route.md +++ b/src/content/release/breaking-changes/navigator-complete-route.md @@ -5,7 +5,7 @@ description: > results could never complete if the route was removed instead of popped. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/network-policy-ios-android.md b/src/content/release/breaking-changes/network-policy-ios-android.md index a3bdf043475..430cd624f97 100644 --- a/src/content/release/breaking-changes/network-policy-ios-android.md +++ b/src/content/release/breaking-changes/network-policy-ios-android.md @@ -5,7 +5,7 @@ description: > the domain is explicitly allowed by policy. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/new-color-scheme-roles.md b/src/content/release/breaking-changes/new-color-scheme-roles.md index dec05b29350..3239b4237a3 100644 --- a/src/content/release/breaking-changes/new-color-scheme-roles.md +++ b/src/content/release/breaking-changes/new-color-scheme-roles.md @@ -7,7 +7,7 @@ description: >- support the newly added colors. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/notifications.md b/src/content/release/breaking-changes/notifications.md index 122da7fe155..ad34ed3106a 100644 --- a/src/content/release/breaking-changes/notifications.md +++ b/src/content/release/breaking-changes/notifications.md @@ -4,7 +4,7 @@ description: > Notifications only traverse ancestors that are notification listeners. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/nullable-cupertinothemedata-brightness.md b/src/content/release/breaking-changes/nullable-cupertinothemedata-brightness.md index 1c7e63545d7..1c13e4dcc48 100644 --- a/src/content/release/breaking-changes/nullable-cupertinothemedata-brightness.md +++ b/src/content/release/breaking-changes/nullable-cupertinothemedata-brightness.md @@ -5,7 +5,7 @@ description: > returns the value specified by the user (defaults to null) as is. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/overlay-entry-rebuilds.md b/src/content/release/breaking-changes/overlay-entry-rebuilds.md index 92cafe8d39b..d15ceb79c99 100644 --- a/src/content/release/breaking-changes/overlay-entry-rebuilds.md +++ b/src/content/release/breaking-changes/overlay-entry-rebuilds.md @@ -3,7 +3,7 @@ title: Rebuild optimization for OverlayEntries and Routes description: OverlayEntries only rebuild on explicit state changes. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/page-transition-replaced-by-ZoomPageTransitionBuilder.md b/src/content/release/breaking-changes/page-transition-replaced-by-ZoomPageTransitionBuilder.md index 0cd4f131333..3fa7ea55a5b 100644 --- a/src/content/release/breaking-changes/page-transition-replaced-by-ZoomPageTransitionBuilder.md +++ b/src/content/release/breaking-changes/page-transition-replaced-by-ZoomPageTransitionBuilder.md @@ -3,7 +3,7 @@ title: Page transitions replaced by ZoomPageTransitionsBuilder description: Using the latest page transition instead of the old one. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/pageview-controller.md b/src/content/release/breaking-changes/pageview-controller.md index d456118e381..f1de8d65036 100644 --- a/src/content/release/breaking-changes/pageview-controller.md +++ b/src/content/release/breaking-changes/pageview-controller.md @@ -4,7 +4,7 @@ description: >- PageView.controller is now nullable. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/paint-enableDithering.md b/src/content/release/breaking-changes/paint-enableDithering.md index 940b1d6fe87..8d4105bdb55 100644 --- a/src/content/release/breaking-changes/paint-enableDithering.md +++ b/src/content/release/breaking-changes/paint-enableDithering.md @@ -4,7 +4,7 @@ description: >- Deprecation of user-configurable `Paint.enableDithering`. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/parent-data-widget-generic-type.md b/src/content/release/breaking-changes/parent-data-widget-generic-type.md index 17426416946..ac8c6de1fca 100644 --- a/src/content/release/breaking-changes/parent-data-widget-generic-type.md +++ b/src/content/release/breaking-changes/parent-data-widget-generic-type.md @@ -3,7 +3,7 @@ title: The generic type of ParentDataWidget changed to ParentData description: The ParentDataWidget is now bound to the ParentData type. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/platform-views-using-html-slots-web.md b/src/content/release/breaking-changes/platform-views-using-html-slots-web.md index f74741f72c4..f9b36c879c3 100644 --- a/src/content/release/breaking-changes/platform-views-using-html-slots-web.md +++ b/src/content/release/breaking-changes/platform-views-using-html-slots-web.md @@ -8,7 +8,7 @@ description: > with video tags or forms potentially losing their state). --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/plugin-api-migration.md b/src/content/release/breaking-changes/plugin-api-migration.md index 0713437dd0e..0756c588c78 100644 --- a/src/content/release/breaking-changes/plugin-api-migration.md +++ b/src/content/release/breaking-changes/plugin-api-migration.md @@ -3,7 +3,7 @@ title: Supporting the new Android plugins APIs description: How to update a plugin using the old APIs to support the new APIs. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} diff --git a/src/content/release/breaking-changes/popscope-with-result.md b/src/content/release/breaking-changes/popscope-with-result.md index 89d96132645..c3e3ab0bb25 100644 --- a/src/content/release/breaking-changes/popscope-with-result.md +++ b/src/content/release/breaking-changes/popscope-with-result.md @@ -5,7 +5,7 @@ description: >- the onPopInvoked function signature. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/primary-scroll-controller-desktop.md b/src/content/release/breaking-changes/primary-scroll-controller-desktop.md index 491babd319a..c0c8fb636e5 100644 --- a/src/content/release/breaking-changes/primary-scroll-controller-desktop.md +++ b/src/content/release/breaking-changes/primary-scroll-controller-desktop.md @@ -5,7 +5,7 @@ description: > vertical `ScrollView`s automatically on Desktop. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/radio-api-redesign.md b/src/content/release/breaking-changes/radio-api-redesign.md index fe8b6175078..a4c83527315 100644 --- a/src/content/release/breaking-changes/radio-api-redesign.md +++ b/src/content/release/breaking-changes/radio-api-redesign.md @@ -4,7 +4,7 @@ description: >- Learn about changes to the radio widget in Flutter 3.35. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/raw-images-on-web-uses-correct-origin-and-colors.md b/src/content/release/breaking-changes/raw-images-on-web-uses-correct-origin-and-colors.md index 618de32fd4c..fabb54b5b94 100644 --- a/src/content/release/breaking-changes/raw-images-on-web-uses-correct-origin-and-colors.md +++ b/src/content/release/breaking-changes/raw-images-on-web-uses-correct-origin-and-colors.md @@ -5,7 +5,7 @@ description: > uses the correct pixel format and starts from the top left corner. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/remove-semantics-elevation-and-thickness.md b/src/content/release/breaking-changes/remove-semantics-elevation-and-thickness.md index 14b37058683..d3e1043995d 100644 --- a/src/content/release/breaking-changes/remove-semantics-elevation-and-thickness.md +++ b/src/content/release/breaking-changes/remove-semantics-elevation-and-thickness.md @@ -4,7 +4,7 @@ description: >- Removed elevation and thickness from semantics properties. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/renderbox-dry-layout.md b/src/content/release/breaking-changes/renderbox-dry-layout.md index 51dd93fa48f..d3fe295e778 100644 --- a/src/content/release/breaking-changes/renderbox-dry-layout.md +++ b/src/content/release/breaking-changes/renderbox-dry-layout.md @@ -5,7 +5,7 @@ description: > correctly calculate its intrinsic size in certain situations. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/rendereditable-layout-before-hit-test.md b/src/content/release/breaking-changes/rendereditable-layout-before-hit-test.md index 6137e59ee9c..9e14347c2ae 100644 --- a/src/content/release/breaking-changes/rendereditable-layout-before-hit-test.md +++ b/src/content/release/breaking-changes/rendereditable-layout-before-hit-test.md @@ -5,7 +5,7 @@ description: > that is only available after the layout. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/rendering-changes.md b/src/content/release/breaking-changes/rendering-changes.md index 6ec8d067a11..95d7b344538 100644 --- a/src/content/release/breaking-changes/rendering-changes.md +++ b/src/content/release/breaking-changes/rendering-changes.md @@ -3,7 +3,7 @@ title: Notable rendering and layout changes after v3.7 description: Non-API related breaking changes made after Flutter v3.7. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Changes diff --git a/src/content/release/breaking-changes/route-information-uri.md b/src/content/release/breaking-changes/route-information-uri.md index be7eb4d86b4..9f7f527a3f2 100644 --- a/src/content/release/breaking-changes/route-information-uri.md +++ b/src/content/release/breaking-changes/route-information-uri.md @@ -3,7 +3,7 @@ title: Migration guide for `RouteInformation.location` description: Deprecation of `RouteInformation.location` and its related APIs. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/route-navigator-refactoring.md b/src/content/release/breaking-changes/route-navigator-refactoring.md index addcc966a02..3f35be237f8 100644 --- a/src/content/release/breaking-changes/route-navigator-refactoring.md +++ b/src/content/release/breaking-changes/route-navigator-refactoring.md @@ -5,7 +5,7 @@ description: > Route and Navigator classes have changed. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/route-transition-record-and-transition-delegate.md b/src/content/release/breaking-changes/route-transition-record-and-transition-delegate.md index c26864cb303..2c1c3487286 100644 --- a/src/content/release/breaking-changes/route-transition-record-and-transition-delegate.md +++ b/src/content/release/breaking-changes/route-transition-record-and-transition-delegate.md @@ -4,7 +4,7 @@ description: > Changes to the rule on how transition delegate resolve route transition. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/routesettings-copywith-migration.md b/src/content/release/breaking-changes/routesettings-copywith-migration.md index 401dab622bf..25ab2bfafbd 100644 --- a/src/content/release/breaking-changes/routesettings-copywith-migration.md +++ b/src/content/release/breaking-changes/routesettings-copywith-migration.md @@ -3,7 +3,7 @@ title: Migration guide for RouteSettings copyWith description: Removal of RouteSettings copyWith and how to migrate --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/scaffold-messenger.md b/src/content/release/breaking-changes/scaffold-messenger.md index b3384c10157..6544f13a679 100644 --- a/src/content/release/breaking-changes/scaffold-messenger.md +++ b/src/content/release/breaking-changes/scaffold-messenger.md @@ -4,7 +4,7 @@ description: > SnackBars are now managed by the ScaffoldMessenger, and persist across routes. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/scribble-text-input-client.md b/src/content/release/breaking-changes/scribble-text-input-client.md index 1f1b581593a..6d5d2fb3104 100644 --- a/src/content/release/breaking-changes/scribble-text-input-client.md +++ b/src/content/release/breaking-changes/scribble-text-input-client.md @@ -5,7 +5,7 @@ description: > to insert or remove text placeholders and show the toolbar. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/scrollable-alert-dialog.md b/src/content/release/breaking-changes/scrollable-alert-dialog.md index 09fc77b32d0..9381bfd078c 100644 --- a/src/content/release/breaking-changes/scrollable-alert-dialog.md +++ b/src/content/release/breaking-changes/scrollable-alert-dialog.md @@ -3,7 +3,7 @@ title: Scrollable AlertDialog (No longer deprecated) description: AlertDialog should scroll automatically when it overflows. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/services-scheduler-dependency-reversed.md b/src/content/release/breaking-changes/services-scheduler-dependency-reversed.md index 7afa652523d..c93b77f8cb6 100644 --- a/src/content/release/breaking-changes/services-scheduler-dependency-reversed.md +++ b/src/content/release/breaking-changes/services-scheduler-dependency-reversed.md @@ -3,7 +3,7 @@ title: Reversing the dependency between the scheduler and services layer description: The services layer now depends on the scheduler layer. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/shortcut-key-event-migration.md b/src/content/release/breaking-changes/shortcut-key-event-migration.md index 9ef96dcd3ae..2c595d58c6d 100644 --- a/src/content/release/breaking-changes/shortcut-key-event-migration.md +++ b/src/content/release/breaking-changes/shortcut-key-event-migration.md @@ -6,7 +6,7 @@ description: > HardwareKeyboard. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/snackbar-with-action-behavior-update.md b/src/content/release/breaking-changes/snackbar-with-action-behavior-update.md index 5e063a411ba..3733a33cdba 100644 --- a/src/content/release/breaking-changes/snackbar-with-action-behavior-update.md +++ b/src/content/release/breaking-changes/snackbar-with-action-behavior-update.md @@ -5,7 +5,7 @@ description: >- manually dismissed by the user. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/splash-screen-migration.md b/src/content/release/breaking-changes/splash-screen-migration.md index 62ed2df8a5c..c367963f3a3 100644 --- a/src/content/release/breaking-changes/splash-screen-migration.md +++ b/src/content/release/breaking-changes/splash-screen-migration.md @@ -3,7 +3,7 @@ title: Deprecated Splash Screen API Migration description: How to migrate from Manifest/Activity defined splash screen. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} Prior to Flutter 2.5, Flutter apps could add a splash screen by defining it within the metadata of their application manifest file diff --git a/src/content/release/breaking-changes/spring-description-underdamped.md b/src/content/release/breaking-changes/spring-description-underdamped.md index 3370dd5bbe9..eda820a4a64 100644 --- a/src/content/release/breaking-changes/spring-description-underdamped.md +++ b/src/content/release/breaking-changes/spring-description-underdamped.md @@ -5,7 +5,7 @@ description: >- affecting underdamped springs (damping ratio less than 1). --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/supplemental-maybeOf-migration.md b/src/content/release/breaking-changes/supplemental-maybeOf-migration.md index 574dcb7e1bf..95a7b3618d7 100644 --- a/src/content/release/breaking-changes/supplemental-maybeOf-migration.md +++ b/src/content/release/breaking-changes/supplemental-maybeOf-migration.md @@ -5,7 +5,7 @@ description: > in the face of null safety. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/system_context_menu_controller_show.md b/src/content/release/breaking-changes/system_context_menu_controller_show.md index fa9ce435f3b..7e5fe310c51 100644 --- a/src/content/release/breaking-changes/system_context_menu_controller_show.md +++ b/src/content/release/breaking-changes/system_context_menu_controller_show.md @@ -5,7 +5,7 @@ description: >- its `showWithItems` method. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/tab-alignment.md b/src/content/release/breaking-changes/tab-alignment.md index 4ef9687c788..09157225ce8 100644 --- a/src/content/release/breaking-changes/tab-alignment.md +++ b/src/content/release/breaking-changes/tab-alignment.md @@ -3,7 +3,7 @@ title: Customizing tabs alignment using the new TabBar.tabAlignment property description: Introducing the TabBar.tabAlignment property. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/target-platform-linux-windows.md b/src/content/release/breaking-changes/target-platform-linux-windows.md index c533e1b00f0..18ade735f2c 100644 --- a/src/content/release/breaking-changes/target-platform-linux-windows.md +++ b/src/content/release/breaking-changes/target-platform-linux-windows.md @@ -5,7 +5,7 @@ description: > require additional cases in switch statements that switch on a TargetPlatform. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/template.md b/src/content/release/breaking-changes/template.md index edf3324e0df..f1336f04d96 100644 --- a/src/content/release/breaking-changes/template.md +++ b/src/content/release/breaking-changes/template.md @@ -1,11 +1,11 @@ --- title: Replace with title of breaking change description: >- - Brief description similar to the "context" section below. + Brief description similar to the "context" section below. Text should break at 80 chars or less. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} {% comment %} PLEASE READ THESE GENERAL INSTRUCTIONS: @@ -18,7 +18,7 @@ description: >- Ideally, submit a PR once you have confirmed info on the version number where the breaking change landed. - * One of the most important things to fill out + * One of the most important things to fill out in this template is the *Timeline* section. For example: `Landed in version: 1.21.0-5.0.pre
    `. Do NOT list the PR in this section. Also, don't @@ -149,7 +149,7 @@ Reverted in version: xxx (OPTIONAL, delete if not used) you link to "main-api.flutter.dev"; prefer our stable documentation if possible. -{% render docs/main-api.md, site: site %} +{% render "docs/main-api.md", site: site %} API documentation: @@ -185,7 +185,7 @@ Relevant PRs: [`ClassName`]: {{site.api}}/flutter/[link_to_relevant_page].html -{% render docs/main-api.md, site: site %} +{% render "docs/main-api.md", site: site %} [`ClassName`]: {{site.main-api}}/flutter/[link_to_relevant_page].html diff --git a/src/content/release/breaking-changes/test-text-input.md b/src/content/release/breaking-changes/test-text-input.md index 662c6d929ef..6210417fdaa 100644 --- a/src/content/release/breaking-changes/test-text-input.md +++ b/src/content/release/breaking-changes/test-text-input.md @@ -3,7 +3,7 @@ title: TestTextInput state reset description: TestTextInput state is now reset between tests. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/test-widgets-flutter-binding-clock.md b/src/content/release/breaking-changes/test-widgets-flutter-binding-clock.md index ce957ea4e99..0ccf0801816 100644 --- a/src/content/release/breaking-changes/test-widgets-flutter-binding-clock.md +++ b/src/content/release/breaking-changes/test-widgets-flutter-binding-clock.md @@ -3,7 +3,7 @@ title: TestWidgetsFlutterBinding.clock change description: The Clock implementation now comes from package:clock. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/text-field-material-localizations.md b/src/content/release/breaking-changes/text-field-material-localizations.md index 59a293e33cb..67ec9b1a47e 100644 --- a/src/content/release/breaking-changes/text-field-material-localizations.md +++ b/src/content/release/breaking-changes/text-field-material-localizations.md @@ -5,7 +5,7 @@ description: > no MaterialLocalizations widget in the widget tree. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/text-input-client-current-value.md b/src/content/release/breaking-changes/text-input-client-current-value.md index 7b466e63f93..255b2dc975c 100644 --- a/src/content/release/breaking-changes/text-input-client-current-value.md +++ b/src/content/release/breaking-changes/text-input-client-current-value.md @@ -5,7 +5,7 @@ description: > get the current TextEditingValue from a client. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/text-selection-theme.md b/src/content/release/breaking-changes/text-selection-theme.md index ad6f3dd8cac..5d26ea43aed 100644 --- a/src/content/release/breaking-changes/text-selection-theme.md +++ b/src/content/release/breaking-changes/text-selection-theme.md @@ -4,7 +4,7 @@ description: > The default properties for text selection are migrating to TextSelectionTheme. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/theme-data-accent-properties.md b/src/content/release/breaking-changes/theme-data-accent-properties.md index ba33d147a84..a2545c5fb7f 100644 --- a/src/content/release/breaking-changes/theme-data-accent-properties.md +++ b/src/content/release/breaking-changes/theme-data-accent-properties.md @@ -5,7 +5,7 @@ description: > accentTextTheme properties have been deprecated. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/toggleable-active-color.md b/src/content/release/breaking-changes/toggleable-active-color.md index 6b2f558328b..d8f82baacb2 100644 --- a/src/content/release/breaking-changes/toggleable-active-color.md +++ b/src/content/release/breaking-changes/toggleable-active-color.md @@ -5,7 +5,7 @@ description: > are migrated to use Material ColorScheme. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/tooltip-semantics-order.md b/src/content/release/breaking-changes/tooltip-semantics-order.md index b9153ae643d..f84978fe3a2 100644 --- a/src/content/release/breaking-changes/tooltip-semantics-order.md +++ b/src/content/release/breaking-changes/tooltip-semantics-order.md @@ -5,7 +5,7 @@ description: >- Tooltip widget's child during accessibility traversal. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/trackpad-gestures.md b/src/content/release/breaking-changes/trackpad-gestures.md index dd9614e32fe..9d0b9a61e3d 100644 --- a/src/content/release/breaking-changes/trackpad-gestures.md +++ b/src/content/release/breaking-changes/trackpad-gestures.md @@ -5,7 +5,7 @@ description: > can trigger pan, drag, and scale `GestureRecognizer` callbacks. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/uiscenedelegate.md b/src/content/release/breaking-changes/uiscenedelegate.md index eaed9062a93..4685a4b7674 100644 --- a/src/content/release/breaking-changes/uiscenedelegate.md +++ b/src/content/release/breaking-changes/uiscenedelegate.md @@ -4,7 +4,7 @@ description: > A guide for Flutter iOS developers to adopt Apple's UISceneDelegate protocol. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} :::note This is an upcoming breaking change that has not yet been finalized or @@ -233,8 +233,7 @@ subclassing `FlutterSceneDelegate`. 1. Open your app in Xcode 2. Right click the **Runner** folder and select **New Empty File** -![New Empty File option in -Xcode](/assets/images/docs/breaking-changes/uiscene-new-file.png) +![New Empty File option in Xcode](/assets/images/docs/breaking-changes/uiscene-new-file.png) For Swift projects, create a `SceneDelegate.swift`: diff --git a/src/content/release/breaking-changes/updated-material-3-progress-indicators.md b/src/content/release/breaking-changes/updated-material-3-progress-indicators.md index eafe4610abc..d466b2a88ed 100644 --- a/src/content/release/breaking-changes/updated-material-3-progress-indicators.md +++ b/src/content/release/breaking-changes/updated-material-3-progress-indicators.md @@ -5,7 +5,7 @@ description: >- have been updated to match the Material 3 Design specifications. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/updated-material-3-slider.md b/src/content/release/breaking-changes/updated-material-3-slider.md index 32c8945b741..bc0b058c4c2 100644 --- a/src/content/release/breaking-changes/updated-material-3-slider.md +++ b/src/content/release/breaking-changes/updated-material-3-slider.md @@ -5,7 +5,7 @@ description: >- Material 3 Design specifications. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/use-maxLengthEnforcement-instead-of-maxLengthEnforced.md b/src/content/release/breaking-changes/use-maxLengthEnforcement-instead-of-maxLengthEnforced.md index 9608a7bbb9a..22472dcc619 100644 --- a/src/content/release/breaking-changes/use-maxLengthEnforcement-instead-of-maxLengthEnforced.md +++ b/src/content/release/breaking-changes/use-maxLengthEnforcement-instead-of-maxLengthEnforced.md @@ -3,7 +3,7 @@ title: Use maxLengthEnforcement instead of maxLengthEnforced description: Introducing the MaxLengthEnforcement enum. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/v1-android-embedding.md b/src/content/release/breaking-changes/v1-android-embedding.md index 55919b3b3d9..680c97dd077 100644 --- a/src/content/release/breaking-changes/v1-android-embedding.md +++ b/src/content/release/breaking-changes/v1-android-embedding.md @@ -4,7 +4,7 @@ description: >- Learn how to account for the removal of the Android v1 embedding APIs. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/visibility-maintainfocusability.md b/src/content/release/breaking-changes/visibility-maintainfocusability.md index 73d861a3cfd..583b3cf8470 100644 --- a/src/content/release/breaking-changes/visibility-maintainfocusability.md +++ b/src/content/release/breaking-changes/visibility-maintainfocusability.md @@ -5,7 +5,7 @@ description: >- for its child when maintainState is enabled. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary This change was introduced to fix an issue diff --git a/src/content/release/breaking-changes/web-golden-comparator.md b/src/content/release/breaking-changes/web-golden-comparator.md index ab3773ed4a4..ec6fb155b70 100644 --- a/src/content/release/breaking-changes/web-golden-comparator.md +++ b/src/content/release/breaking-changes/web-golden-comparator.md @@ -7,7 +7,7 @@ description: >- `goldenFileComparator` directly. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/wide-gamut-cupertino-dynamic-color.md b/src/content/release/breaking-changes/wide-gamut-cupertino-dynamic-color.md index a1819419fe5..85558c90bca 100644 --- a/src/content/release/breaking-changes/wide-gamut-cupertino-dynamic-color.md +++ b/src/content/release/breaking-changes/wide-gamut-cupertino-dynamic-color.md @@ -5,7 +5,7 @@ description: >- align with wide gamut Color API. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/wide-gamut-framework.md b/src/content/release/breaking-changes/wide-gamut-framework.md index b92ef5106a7..0357886c6f5 100644 --- a/src/content/release/breaking-changes/wide-gamut-framework.md +++ b/src/content/release/breaking-changes/wide-gamut-framework.md @@ -4,7 +4,7 @@ description: >- Changes to support wide gamut color and migration instructions. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/win-lifecycle-process-function.md b/src/content/release/breaking-changes/win-lifecycle-process-function.md index 0c5539f8ecf..88eda646e14 100644 --- a/src/content/release/breaking-changes/win-lifecycle-process-function.md +++ b/src/content/release/breaking-changes/win-lifecycle-process-function.md @@ -5,7 +5,7 @@ description: >- be considered for application lifecycle events. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/window-singleton.md b/src/content/release/breaking-changes/window-singleton.md index 5d875428523..37240d77e23 100644 --- a/src/content/release/breaking-changes/window-singleton.md +++ b/src/content/release/breaking-changes/window-singleton.md @@ -5,7 +5,7 @@ description: > multiple windows the window singleton has been deprecated. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/windows-build-architecture.md b/src/content/release/breaking-changes/windows-build-architecture.md index 0b1c7b1a75f..4784324ead1 100644 --- a/src/content/release/breaking-changes/windows-build-architecture.md +++ b/src/content/release/breaking-changes/windows-build-architecture.md @@ -5,7 +5,7 @@ description: >- the Windows build path was updated to include the target architecture. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/breaking-changes/windows-dark-mode.md b/src/content/release/breaking-changes/windows-dark-mode.md index 8dd15fa5e75..98c56721876 100644 --- a/src/content/release/breaking-changes/windows-dark-mode.md +++ b/src/content/release/breaking-changes/windows-dark-mode.md @@ -3,7 +3,7 @@ title: Migrate a Windows project to support dark title bars description: How to update a Windows project to support dark title bars --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} Projects created before Flutter 3.7 have light title bars even when the Windows theme is dark mode. Projects created before diff --git a/src/content/release/breaking-changes/windows-run-loop.md b/src/content/release/breaking-changes/windows-run-loop.md index 38dc79bcbd9..1cf30476920 100644 --- a/src/content/release/breaking-changes/windows-run-loop.md +++ b/src/content/release/breaking-changes/windows-run-loop.md @@ -3,7 +3,7 @@ title: Migrate a Windows project to the idiomatic run loop description: How to update a Windows project to use the idiomatic run loop --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} Flutter 2.5 replaced Windows apps' run loop with an idiomatic Windows message pump to reduce CPU usage. diff --git a/src/content/release/breaking-changes/windows-show-window-migration.md b/src/content/release/breaking-changes/windows-show-window-migration.md index bcbaf8a3e51..214f2f0e353 100644 --- a/src/content/release/breaking-changes/windows-show-window-migration.md +++ b/src/content/release/breaking-changes/windows-show-window-migration.md @@ -3,7 +3,7 @@ title: Migrate a Windows project to ensure the window is shown description: How to update a Windows project to ensure the window is shown --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} Flutter 3.13 fixed a [bug][] that could result in the window not being shown. Windows projects created using Flutter 3.7 or Flutter 3.10 need to be migrated diff --git a/src/content/release/breaking-changes/windows-version-information.md b/src/content/release/breaking-changes/windows-version-information.md index c6f9268efd4..ec2d5da4527 100644 --- a/src/content/release/breaking-changes/windows-version-information.md +++ b/src/content/release/breaking-changes/windows-version-information.md @@ -3,7 +3,7 @@ title: Migrate a Windows project to set version information description: How to update a Windows project to set version information --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} Flutter 3.3 added support for setting the Windows app's version from the `pubspec.yaml` file or through the `--build-name` and `--build-number` diff --git a/src/content/release/breaking-changes/zone-errors.md b/src/content/release/breaking-changes/zone-errors.md index 790549eac22..3387c223a05 100644 --- a/src/content/release/breaking-changes/zone-errors.md +++ b/src/content/release/breaking-changes/zone-errors.md @@ -5,7 +5,7 @@ description: > than the Zone used for `runApp`, a warning is printed to the console. --- -{% render docs/breaking-changes.md %} +{% render "docs/breaking-changes.md" %} ## Summary diff --git a/src/content/release/release-notes/changelogs/changelog-1.12.13.md b/src/content/release/release-notes/changelogs/changelog-1.12.13.md index 34c63e496c1..1571c050e10 100644 --- a/src/content/release/release-notes/changelogs/changelog-1.12.13.md +++ b/src/content/release/release-notes/changelogs/changelog-1.12.13.md @@ -2,6 +2,7 @@ title: Change log for Flutter 1.12.13 shortTitle: 1.12.13 change log description: Change log for Flutter 1.12.13 containing a list of all PRs merged for this release. +skipTemplateRendering: true --- ## PRs closed in this release of flutter/flutter diff --git a/src/content/release/release-notes/changelogs/changelog-1.2.1.md b/src/content/release/release-notes/changelogs/changelog-1.2.1.md index 09134039742..ec4e6a97aa6 100644 --- a/src/content/release/release-notes/changelogs/changelog-1.2.1.md +++ b/src/content/release/release-notes/changelogs/changelog-1.2.1.md @@ -2,6 +2,7 @@ title: Change log for Flutter 1.2.2 shortTitle: 1.2.2 change log description: Change log for Flutter 1.2.2 containing a list of all PRs merged for this release. +skipTemplateRendering: true --- diff --git a/src/content/release/release-notes/changelogs/changelog-1.5.4.md b/src/content/release/release-notes/changelogs/changelog-1.5.4.md index fff4855d285..353fdbc3791 100644 --- a/src/content/release/release-notes/changelogs/changelog-1.5.4.md +++ b/src/content/release/release-notes/changelogs/changelog-1.5.4.md @@ -2,6 +2,7 @@ title: Change log for Flutter 1.5.4 shortTitle: 1.5.4 change log description: Change log for Flutter 1.5.4 containing a list of all PRs merged for this release. +skipTemplateRendering: true --- ## PRs closed in this release of flutter/flutter diff --git a/src/content/release/release-notes/changelogs/changelog-1.7.8.md b/src/content/release/release-notes/changelogs/changelog-1.7.8.md index a233009e2df..8b6d5d74e77 100644 --- a/src/content/release/release-notes/changelogs/changelog-1.7.8.md +++ b/src/content/release/release-notes/changelogs/changelog-1.7.8.md @@ -2,6 +2,7 @@ title: Change log for Flutter 1.7.8 shortTitle: 1.7.8 change log description: Change log for Flutter 1.7.8 containing a list of all PRs merged for this release. +skipTemplateRendering: true --- diff --git a/src/content/release/release-notes/changelogs/changelog-1.9.1.md b/src/content/release/release-notes/changelogs/changelog-1.9.1.md index c3ec58fd1de..7a58d7d27c4 100644 --- a/src/content/release/release-notes/changelogs/changelog-1.9.1.md +++ b/src/content/release/release-notes/changelogs/changelog-1.9.1.md @@ -2,6 +2,7 @@ title: Change log for Flutter 1.9.1 shortTitle: 1.9.1 change log description: Change log for Flutter 1.9.1 containing a list of all PRs merged for this release. +skipTemplateRendering: true --- diff --git a/src/content/release/release-notes/release-notes-0.0.21-1.0.0.md b/src/content/release/release-notes/release-notes-0.0.21-1.0.0.md index 1a92660a7e1..508206187f9 100644 --- a/src/content/release/release-notes/release-notes-0.0.21-1.0.0.md +++ b/src/content/release/release-notes/release-notes-0.0.21-1.0.0.md @@ -2,6 +2,7 @@ title: Flutter Changelog 0.0.21 - 1.0.0 shortTitle: Flutter Changelog up to 1.0.0 description: Archived Changelog wiki page, containing release information between Flutter 0.0.21 and 1.0.0. +skipTemplateRendering: true --- _This page is a dump of the old Changelog page from the Flutter wiki up until diff --git a/src/content/release/release-notes/release-notes-1.12.13.md b/src/content/release/release-notes/release-notes-1.12.13.md index f9a805561ab..628d70fdf8d 100644 --- a/src/content/release/release-notes/release-notes-1.12.13.md +++ b/src/content/release/release-notes/release-notes-1.12.13.md @@ -2,6 +2,7 @@ title: Flutter 1.12.13 release notes shortTitle: 1.12.13 release notes description: Release notes for Flutter 1.12.13. +skipTemplateRendering: true --- Welcome to Flutter 1.12, our biggest stable release so far! diff --git a/src/content/release/release-notes/release-notes-1.17.0.md b/src/content/release/release-notes/release-notes-1.17.0.md index b2e85b444f9..72dd97cbe4b 100644 --- a/src/content/release/release-notes/release-notes-1.17.0.md +++ b/src/content/release/release-notes/release-notes-1.17.0.md @@ -2,6 +2,7 @@ title: Flutter 1.17.0 release notes shortTitle: 1.17.0 release notes description: Release notes for Flutter 1.17.0. +skipTemplateRendering: true --- ## Merged pull requests by label diff --git a/src/content/release/release-notes/release-notes-1.2.1.md b/src/content/release/release-notes/release-notes-1.2.1.md index 48285f33017..159274ed2a9 100644 --- a/src/content/release/release-notes/release-notes-1.2.1.md +++ b/src/content/release/release-notes/release-notes-1.2.1.md @@ -2,6 +2,7 @@ title: Flutter 1.2.1 release notes shortTitle: 1.2.1 release notes description: Release notes for Flutter 1.2.1. +skipTemplateRendering: true --- Our #1 priority since the Flutter v1.0 release has been to diff --git a/src/content/release/release-notes/release-notes-1.20.0.md b/src/content/release/release-notes/release-notes-1.20.0.md index 6ba6669f97e..9a149a0ac46 100644 --- a/src/content/release/release-notes/release-notes-1.20.0.md +++ b/src/content/release/release-notes/release-notes-1.20.0.md @@ -2,6 +2,7 @@ title: Flutter 1.20.0 release notes shortTitle: 1.20.0 release notes description: Release notes for Flutter 1.20.0. +skipTemplateRendering: true --- ## Merged pull requests by label diff --git a/src/content/release/release-notes/release-notes-1.22.0.md b/src/content/release/release-notes/release-notes-1.22.0.md index cf66a1faa83..9694e0e6a30 100644 --- a/src/content/release/release-notes/release-notes-1.22.0.md +++ b/src/content/release/release-notes/release-notes-1.22.0.md @@ -2,6 +2,7 @@ title: Flutter 1.22.0 release notes shortTitle: 1.22.0 release notes description: Release notes for Flutter 1.22.0. +skipTemplateRendering: true --- This page has release notes for 1.22.0. diff --git a/src/content/release/release-notes/release-notes-1.5.4.md b/src/content/release/release-notes/release-notes-1.5.4.md index 49725e09ce5..e500c201913 100644 --- a/src/content/release/release-notes/release-notes-1.5.4.md +++ b/src/content/release/release-notes/release-notes-1.5.4.md @@ -2,6 +2,7 @@ title: Flutter 1.5.4 release notes shortTitle: 1.5.4 release notes description: Release notes for Flutter 1.5.4. +skipTemplateRendering: true --- In addition to continuing to focus on quality and stability since the 1.2 release, the Flutter 1.5.4 stable release adds a set of new features as we approach the Google I/O conference. Further, [Apple has a deadline for building against the 12.1 version of their iOS SDK](https://developer.apple.com/news/?id=03202019a), which we now do in this update. You can meet Apple's requirements simply by pulling down the 1.5.4 stable release, building and updating your Flutter app in the Apple Store. diff --git a/src/content/release/release-notes/release-notes-1.7.8.md b/src/content/release/release-notes/release-notes-1.7.8.md index 6e7cbe5ef7a..219d1f499a9 100644 --- a/src/content/release/release-notes/release-notes-1.7.8.md +++ b/src/content/release/release-notes/release-notes-1.7.8.md @@ -2,6 +2,7 @@ title: Flutter 1.7.8 release notes shortTitle: 1.7.8 release notes description: Release notes for Flutter 1.7.8. +skipTemplateRendering: true --- The 1.7.8 release is a follow-on to the 1.5.4 stable release in May, diff --git a/src/content/release/release-notes/release-notes-1.9.1.md b/src/content/release/release-notes/release-notes-1.9.1.md index 9151dc6674a..74e9eba3c2b 100644 --- a/src/content/release/release-notes/release-notes-1.9.1.md +++ b/src/content/release/release-notes/release-notes-1.9.1.md @@ -2,6 +2,7 @@ title: Flutter 1.9.1 release notes shortTitle: 1.9.1 release notes description: Release notes for Flutter 1.9.1. +skipTemplateRendering: true --- Hello and welcome to another stable release of Flutter. So far this year, we've been right on target with one stable release each quarter, as per [our plan](https://github.com/flutter/flutter/blob/master/docs/releases/Flutter-build-release-channels.md) (well, less of a plan and more of a goal, but still, it's been working out pretty well so far…). This release is our biggest yet, with 620 Pull Requests merged from 116 contributors. As always, the interesting PRs are listed below. And there are lots of interesting things to discuss in this release, including: diff --git a/src/content/release/release-notes/release-notes-2.0.0.md b/src/content/release/release-notes/release-notes-2.0.0.md index 14f9d3def46..19d253fb646 100644 --- a/src/content/release/release-notes/release-notes-2.0.0.md +++ b/src/content/release/release-notes/release-notes-2.0.0.md @@ -2,6 +2,7 @@ title: Flutter 2.0.0 release notes shortTitle: 2.0.0 release notes description: Release notes for Flutter 2.0.0. +skipTemplateRendering: true --- This page has release notes for 2.0.0. diff --git a/src/content/release/release-notes/release-notes-2.10.0.md b/src/content/release/release-notes/release-notes-2.10.0.md index e72bc0fc800..54ef1f5303a 100644 --- a/src/content/release/release-notes/release-notes-2.10.0.md +++ b/src/content/release/release-notes/release-notes-2.10.0.md @@ -2,7 +2,9 @@ title: Flutter 2.10.0 release notes shortTitle: 2.10.0 release notes description: Release notes for Flutter 2.10.0. +skipTemplateRendering: true --- + This page has release notes for 2.10.0. For information about subsequent bug-fix releases, see our [CHANGELOG][] diff --git a/src/content/release/release-notes/release-notes-2.2.0.md b/src/content/release/release-notes/release-notes-2.2.0.md index d74f6ec2364..517c6c6d4da 100644 --- a/src/content/release/release-notes/release-notes-2.2.0.md +++ b/src/content/release/release-notes/release-notes-2.2.0.md @@ -2,7 +2,9 @@ title: Flutter 2.2.0 release notes shortTitle: 2.2.0 release notes description: Release notes for Flutter 2.2.0. +skipTemplateRendering: true --- + This page has release notes for 2.2.0. For information about subsequent bug-fix releases, see our [CHANGELOG][] diff --git a/src/content/release/release-notes/release-notes-2.5.0.md b/src/content/release/release-notes/release-notes-2.5.0.md index 61181bb324c..151be815673 100644 --- a/src/content/release/release-notes/release-notes-2.5.0.md +++ b/src/content/release/release-notes/release-notes-2.5.0.md @@ -2,7 +2,9 @@ title: Flutter 2.5.0 release notes shortTitle: 2.5.0 release notes description: Release notes for Flutter 2.5.0. +skipTemplateRendering: true --- + This page has release notes for 2.5.0. For information about subsequent bug-fix releases, see our [CHANGELOG][] diff --git a/src/content/release/release-notes/release-notes-2.8.0.md b/src/content/release/release-notes/release-notes-2.8.0.md index a91cf012696..867e196fb6d 100644 --- a/src/content/release/release-notes/release-notes-2.8.0.md +++ b/src/content/release/release-notes/release-notes-2.8.0.md @@ -2,7 +2,9 @@ title: Flutter 2.8.0 release notes shortTitle: 2.8.0 release notes description: Release notes for Flutter 2.8.0. +skipTemplateRendering: true --- + This page has release notes for 2.8.0. For information about subsequent bug-fix releases, see our [CHANGELOG][] diff --git a/src/content/release/release-notes/release-notes-3.0.0.md b/src/content/release/release-notes/release-notes-3.0.0.md index 7b2aa0aa064..f1e6c3f0bd3 100644 --- a/src/content/release/release-notes/release-notes-3.0.0.md +++ b/src/content/release/release-notes/release-notes-3.0.0.md @@ -2,6 +2,7 @@ title: Flutter 3.0.0 release notes shortTitle: 3.0.0 release notes description: Release notes for Flutter 3.0.0. +skipTemplateRendering: true --- This page has release notes for 3.0.0. diff --git a/src/content/release/release-notes/release-notes-3.10.0.md b/src/content/release/release-notes/release-notes-3.10.0.md index fa8ae554a57..861e562e29d 100644 --- a/src/content/release/release-notes/release-notes-3.10.0.md +++ b/src/content/release/release-notes/release-notes-3.10.0.md @@ -2,7 +2,9 @@ title: Flutter 3.10.0 release notes shortTitle: 3.10.0 release notes description: Release notes for Flutter 3.10.0. +skipTemplateRendering: true --- + This page has release notes for 3.10.0. For information about subsequent bug-fix releases, see our [CHANGELOG][]. diff --git a/src/content/release/release-notes/release-notes-3.13.0.md b/src/content/release/release-notes/release-notes-3.13.0.md index a17df8cf232..bab38ee2206 100644 --- a/src/content/release/release-notes/release-notes-3.13.0.md +++ b/src/content/release/release-notes/release-notes-3.13.0.md @@ -2,7 +2,9 @@ title: Flutter 3.13.0 release notes shortTitle: 3.13.0 release notes description: Release notes for Flutter 3.13.0. +skipTemplateRendering: true --- + This page has release notes for 3.13.0. For information about subsequent bug-fix releases, see our [CHANGELOG][]. diff --git a/src/content/release/release-notes/release-notes-3.16.0.md b/src/content/release/release-notes/release-notes-3.16.0.md index 3b9770b1550..da418dab4e9 100644 --- a/src/content/release/release-notes/release-notes-3.16.0.md +++ b/src/content/release/release-notes/release-notes-3.16.0.md @@ -2,6 +2,7 @@ title: Flutter 3.16.0 release notes shortTitle: 3.16.0 release notes description: Release notes for Flutter 3.16.0. +skipTemplateRendering: true --- This page has release notes for 3.16.0. diff --git a/src/content/release/release-notes/release-notes-3.19.0.md b/src/content/release/release-notes/release-notes-3.19.0.md index d43f6ff40d2..41bfc1e82b7 100644 --- a/src/content/release/release-notes/release-notes-3.19.0.md +++ b/src/content/release/release-notes/release-notes-3.19.0.md @@ -2,6 +2,7 @@ title: Flutter 3.19.0 release notes shortTitle: 3.19.0 release notes description: Release notes for Flutter 3.19.0. +skipTemplateRendering: true --- This page has release notes for 3.19.0. diff --git a/src/content/release/release-notes/release-notes-3.22.0.md b/src/content/release/release-notes/release-notes-3.22.0.md index 707b9a68797..f83f9502b50 100644 --- a/src/content/release/release-notes/release-notes-3.22.0.md +++ b/src/content/release/release-notes/release-notes-3.22.0.md @@ -2,6 +2,7 @@ title: Flutter 3.22.0 release notes shortTitle: 3.22.0 release notes description: Release notes for Flutter 3.22.0. +skipTemplateRendering: true --- This page has release notes for 3.22.0. diff --git a/src/content/release/release-notes/release-notes-3.24.0.md b/src/content/release/release-notes/release-notes-3.24.0.md index a40353d4383..12699482f2c 100644 --- a/src/content/release/release-notes/release-notes-3.24.0.md +++ b/src/content/release/release-notes/release-notes-3.24.0.md @@ -2,6 +2,7 @@ title: Flutter 3.24.0 release notes shortTitle: 3.24.0 release notes description: Release notes for Flutter 3.24.0. +skipTemplateRendering: true --- This page has release notes for 3.24.0. diff --git a/src/content/release/release-notes/release-notes-3.27.0.md b/src/content/release/release-notes/release-notes-3.27.0.md index a79874dc62e..04b374deb30 100644 --- a/src/content/release/release-notes/release-notes-3.27.0.md +++ b/src/content/release/release-notes/release-notes-3.27.0.md @@ -2,6 +2,7 @@ title: Flutter 3.27.0 release notes shortTitle: 3.27.0 release notes description: Release notes for Flutter 3.27.0. +skipTemplateRendering: true --- This page has release notes for 3.27.0. diff --git a/src/content/release/release-notes/release-notes-3.29.0.md b/src/content/release/release-notes/release-notes-3.29.0.md index b4f371e358f..929dcde06f0 100644 --- a/src/content/release/release-notes/release-notes-3.29.0.md +++ b/src/content/release/release-notes/release-notes-3.29.0.md @@ -2,6 +2,7 @@ title: Flutter 3.29.0 release notes shortTitle: 3.29.0 release notes description: Release notes for Flutter 3.29.0. +skipTemplateRendering: true --- This page has release notes for 3.29.0. diff --git a/src/content/release/release-notes/release-notes-3.3.0.md b/src/content/release/release-notes/release-notes-3.3.0.md index 4d154cd7594..d84f7dc7505 100644 --- a/src/content/release/release-notes/release-notes-3.3.0.md +++ b/src/content/release/release-notes/release-notes-3.3.0.md @@ -2,6 +2,7 @@ title: Flutter 3.3.0 release notes shortTitle: 3.3.0 release notes description: Release notes for Flutter 3.3.0. +skipTemplateRendering: true --- This page has release notes for 3.3.0. diff --git a/src/content/release/release-notes/release-notes-3.32.0.md b/src/content/release/release-notes/release-notes-3.32.0.md index d914ba1e05e..ce92e19c7cb 100644 --- a/src/content/release/release-notes/release-notes-3.32.0.md +++ b/src/content/release/release-notes/release-notes-3.32.0.md @@ -2,6 +2,7 @@ title: Flutter 3.32.0 release notes shortTitle: 3.32.0 release notes description: Release notes for Flutter 3.32.0. +skipTemplateRendering: true --- This page has release notes for 3.32.0. diff --git a/src/content/release/release-notes/release-notes-3.35.0.md b/src/content/release/release-notes/release-notes-3.35.0.md index 052b64f5951..178d1e3ba63 100644 --- a/src/content/release/release-notes/release-notes-3.35.0.md +++ b/src/content/release/release-notes/release-notes-3.35.0.md @@ -2,6 +2,7 @@ title: Flutter 3.35.0 release notes shortTitle: 3.35.0 release notes description: Release notes for Flutter 3.35.0. +skipTemplateRendering: true --- This page has release notes for 3.35.0. diff --git a/src/content/release/release-notes/release-notes-3.7.0.md b/src/content/release/release-notes/release-notes-3.7.0.md index 39203063c4b..de3b0a59578 100644 --- a/src/content/release/release-notes/release-notes-3.7.0.md +++ b/src/content/release/release-notes/release-notes-3.7.0.md @@ -2,7 +2,9 @@ title: Flutter 3.7.0 release notes shortTitle: 3.7.0 release notes description: Release notes for Flutter 3.7.0. +skipTemplateRendering: true --- + This page has release notes for 3.7.0. For information about subsequent bug-fix releases, see our [CHANGELOG][]. diff --git a/src/content/resources/ads-overview.md b/src/content/resources/ads-overview.md index 3a38f7e8825..69a210350ac 100644 --- a/src/content/resources/ads-overview.md +++ b/src/content/resources/ads-overview.md @@ -3,6 +3,7 @@ title: Ads overview description: > Learn about the resources available for adding ads to your Flutter app. +showBreadcrumbs: false --- ![adding ads](/assets/images/docs/add-ads.png) diff --git a/src/content/resources/ai-overview.md b/src/content/resources/ai-overview.md index 0c3aa248fb0..5006792764d 100644 --- a/src/content/resources/ai-overview.md +++ b/src/content/resources/ai-overview.md @@ -3,9 +3,10 @@ title: AI description: > Learn about the resources available for adding generative AI to your Flutter application. +showBreadcrumbs: false --- -{% ytEmbed '1AuzJEiHjO4', 'Quick overview of the Google AI Dart SDK' %} + The Google AI Dart SDK enables you to use Google's state-of-the-art generative AI models (like Gemini) diff --git a/src/content/resources/architectural-overview.md b/src/content/resources/architectural-overview.md index 11c1ea39268..ad9f3ccd417 100644 --- a/src/content/resources/architectural-overview.md +++ b/src/content/resources/architectural-overview.md @@ -3,6 +3,7 @@ title: Flutter architectural overview description: > A high-level overview of the architecture of Flutter, including the core principles and concepts that form its design. +showBreadcrumbs: false --- diff --git a/src/content/resources/bootstrap-into-dart.md b/src/content/resources/bootstrap-into-dart.md index 3a71105e7c8..b2cce3539cd 100644 --- a/src/content/resources/bootstrap-into-dart.md +++ b/src/content/resources/bootstrap-into-dart.md @@ -1,6 +1,7 @@ --- title: Bootstrap into Dart description: How to get started with the Dart programming language. +showBreadcrumbs: false --- New to the [Dart][] language? diff --git a/src/content/resources/bug-reports.md b/src/content/resources/bug-reports.md index 70a66f4a13d..211c25e696e 100644 --- a/src/content/resources/bug-reports.md +++ b/src/content/resources/bug-reports.md @@ -3,6 +3,7 @@ title: Create useful bug reports description: > Where to file bug reports and enhancement requests for flutter and the website. +showBreadcrumbs: false --- The instructions in this document detail the current steps diff --git a/src/content/resources/courses.md b/src/content/resources/courses.md index 10143373e19..44a732197f8 100644 --- a/src/content/resources/courses.md +++ b/src/content/resources/courses.md @@ -1,6 +1,7 @@ --- title: Online courses description: An index of online courses teaching Flutter development. +showBreadcrumbs: false --- Learn how to build Flutter apps with these video courses. diff --git a/src/content/resources/faq.md b/src/content/resources/faq.md index 02cf55ccab7..8c20236e697 100644 --- a/src/content/resources/faq.md +++ b/src/content/resources/faq.md @@ -1,6 +1,7 @@ --- title: FAQ description: Frequently asked questions and answers about Flutter. +showBreadcrumbs: false --- ## Introduction diff --git a/src/content/resources/games-toolkit.md b/src/content/resources/games-toolkit.md index ee5e48e29de..b28dd46f604 100644 --- a/src/content/resources/games-toolkit.md +++ b/src/content/resources/games-toolkit.md @@ -2,6 +2,7 @@ title: Casual Games Toolkit description: >- Learn about free & open source multiplatform 2D game development in Flutter. +showBreadcrumbs: false --- The Flutter Casual Games Toolkit pulls together new and existing resources diff --git a/src/content/resources/in-app-purchases-overview.md b/src/content/resources/in-app-purchases-overview.md index 231015d7229..10aa2875bae 100644 --- a/src/content/resources/in-app-purchases-overview.md +++ b/src/content/resources/in-app-purchases-overview.md @@ -3,6 +3,7 @@ title: In-app purchases overview description: > Learn about the resources available for adding in-app purchases to your Flutter app. +showBreadcrumbs: false --- ![adding ads](/assets/images/docs/add-in-app-purchases.png) diff --git a/src/content/resources/inside-flutter.md b/src/content/resources/inside-flutter.md index d5b2494925a..3198f5ccc25 100644 --- a/src/content/resources/inside-flutter.md +++ b/src/content/resources/inside-flutter.md @@ -1,6 +1,8 @@ --- title: Inside Flutter -description: Learn about Flutter's inner workings from one of the founding engineers. +description: >- + Learn about Flutter's inner workings from one of the founding engineers. +showBreadcrumbs: false --- This document describes the inner workings of the Flutter toolkit that make diff --git a/src/content/resources/news-toolkit.md b/src/content/resources/news-toolkit.md index ae584a6b75d..620d3523452 100644 --- a/src/content/resources/news-toolkit.md +++ b/src/content/resources/news-toolkit.md @@ -1,6 +1,7 @@ --- title: Flutter News Toolkit description: Learn more about creating a newsfeed app in Flutter. +showBreadcrumbs: false --- The Flutter News Toolkit is now maintained by Very Good Ventures (VGV). diff --git a/src/content/resources/payments-overview.md b/src/content/resources/payments-overview.md index 4d3da473c34..2cb91e1dec1 100644 --- a/src/content/resources/payments-overview.md +++ b/src/content/resources/payments-overview.md @@ -3,6 +3,7 @@ title: Payments overview description: > Learn about the resources available for Google pay and other services to your Flutter app. +showBreadcrumbs: false --- ![adding ads](/assets/images/docs/add-payments.png) @@ -10,7 +11,7 @@ description: > Seamlessly accept payments with multiple providers in your Flutter app -The the following resource can help to get you started: +The following resource can help to get you started: * [Add ads to your mobile Flutter app or game][] (cookbook recipe) diff --git a/src/content/resources/resources.json b/src/content/resources/resources.json deleted file mode 100644 index b18625462fc..00000000000 --- a/src/content/resources/resources.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "showBreadcrumbs": false -} diff --git a/src/content/resources/support.md b/src/content/resources/support.md index 5cda9b566a5..ac1e6a66f83 100644 --- a/src/content/resources/support.md +++ b/src/content/resources/support.md @@ -1,6 +1,7 @@ --- title: Flutter support description: Where can you get support when developing with Flutter. +showBreadcrumbs: false --- Welcome! diff --git a/src/content/resources/videos.md b/src/content/resources/videos.md index 887aad0a1ed..1e3694d258a 100644 --- a/src/content/resources/videos.md +++ b/src/content/resources/videos.md @@ -2,6 +2,7 @@ title: Videos description: > Available videos on various aspects of developing in Flutter. +showBreadcrumbs: false --- These Flutter videos, produced both internally @@ -22,7 +23,7 @@ some in different languages. Even if you couldn't make it to Nairobi for the in-person event, you can enjoy the content created for Flutter Forward! -{% ytEmbed 'zKQYGKAe5W8?start=2778', 'Flutter Forward 2023 Livestream' %} + [Flutter Forward playlist][] @@ -36,7 +37,7 @@ featuring new content and activities leading up to the event. This playlist contains these and other pre-event videos relating to Flutter Forward. -{% ytEmbed 'hpgkrUPRBjc?start=6', 'Prepare for Flutter Forward 2023 - 17 days of Flutter' %} + **17 Days of Flutter!** @@ -61,7 +62,7 @@ learn alongside her as she asks important questions like: "What is the best way to build out a theme? How to approach using fonts?" And more! -{% ytEmbed 'CkcvVZZEsJE', 'Building my first Flutter app | Learning to Fly' %} + [Learning to Fly playlist][] @@ -82,7 +83,7 @@ and general advice on getting the most out of Flutter. In the comments section for this series, you can submit suggestions future episodes. -{% ytEmbed 'QIW35-vcA2o', 'Introducing Decoding Flutter - Flutter best practices' %} + [Decoding Flutter playlist][] @@ -93,7 +94,7 @@ you can submit suggestions future episodes. Do you have 60 seconds? Each one-minute video highlights a Flutter widget. -{% ytEmbed 'b_sQ9bMltGU', 'Introducing Flutter widget of the week' %} + [Flutter widget of the week playlist][] @@ -104,7 +105,7 @@ Each one-minute video highlights a Flutter widget. If you have another minute (or two), each of these videos highlights a Flutter package. -{% ytEmbed 'QFcFEpFmNJ8', 'Introducing Flutter package of the week' %} + [Flutter package of the week playlist][] @@ -116,7 +117,7 @@ This series features Flutter programmers coding, unscripted and in real time. Mistakes, solutions (some of them correct), and snazzy intro music included. -{% ytEmbed 'vqPG1tU6-c0', 'Introducing The Boring Show - Flutter live coding' %} + [The Boring Flutter show playlist][] @@ -127,7 +128,7 @@ unscripted and in real time. Mistakes, solutions Google I/O 2022 is over, but you can still catch the great Flutter content! -{% ytEmbed 'w_ezWG1yKQQ', 'What\'s new in Flutter at Google I/O 2022' %} + [Flutter at Google I/O playlist][] @@ -142,17 +143,17 @@ officially launched Flutter 2. Check out the Flutter Engage 2021 highlights reel. -{% ytEmbed 'IdrCyS7EF8M', 'Top 10 highlights from Flutter Engage 2021' %} + Watch recordings of the sessions on the Flutter YouTube channel. -{% ytEmbed 'zSbsIiluixw', 'Flutter Engage 2021 keynote' %} + [Flutter Engage 2021 playlist][] Watch recordings of the sessions offered by the Flutter community. -{% ytEmbed '-_de6IfY2RU', 'Choreographing transitions with Flutter\'s animation framework' %} + [Flutter Engage community talks playlist][] @@ -163,7 +164,7 @@ Watch recordings of the sessions offered by the Flutter community. Five-to-ten minute tutorials (more or less) on using Flutter. -{% ytEmbed 'wgTBLj7rMPM', 'Introducing Flutter in Focus - Flutter tutorials' %} + [Flutter in focus playlist][] @@ -173,7 +174,7 @@ Five-to-ten minute tutorials (more or less) on using Flutter. Here are a some Flutter talks given at various conferences. -{% ytEmbed 'd_m5csmrf7I', 'Pragmatic state management in Flutter' %} + [Conference talks playlist][] @@ -185,7 +186,7 @@ Videos showing how various customers, such as Abbey Road Studio, Hamilton, and Alibaba, have used Flutter to create beautiful compelling apps with millions of downloads. -{% ytEmbed '_ACWeGGBP4E', 'Flutter developer stories' %} + [Flutter developer stories playlist][] diff --git a/src/content/robots.liquid b/src/content/robots.liquid deleted file mode 100644 index 67329946b34..00000000000 --- a/src/content/robots.liquid +++ /dev/null @@ -1,17 +0,0 @@ ---- -layout: none -permalink: robots.txt ---- - -{%- if isProduction == true -%} -User-agent: * -Disallow: - -Sitemap: https://docs.flutter.dev/sitemap.xml -{%- else -%} -User-agent: linkcheck -Disallow: - -User-agent: * -Disallow: / -{% endif -%} diff --git a/src/content/sitemap.liquid b/src/content/sitemap.liquid deleted file mode 100644 index 7e38bc4e472..00000000000 --- a/src/content/sitemap.liquid +++ /dev/null @@ -1,32 +0,0 @@ ---- -layout: none -sitemap: false -permalink: sitemap.xml ---- - - - -{% assign pages = collections.all | sort: 'url' %} - -{%- for page in pages -%} - -{%- if page.url and page.data.sitemap != false and page.data.title -%} - - {{ site.url }}{{ page.url | regexReplace: '/index(\.html)?$|\.html$|/$' }} - - {%- if page.data.sitemap.lastmod -%} - {{ page.data.sitemap.lastmod | date: "%Y-%m-%d" }} - {%- else -%} - {% assign date = site.now | default: page.date | default: site.time -%} - {{ date | toISOString }} - {%- endif -%} - - {{ page.data.sitemap.changefreq | default: 'monthly' }} - {% if page.data.sitemap.priority -%} - {{ page.data.sitemap.priority }} - {%- endif -%} - -{% endif -%} - -{%- endfor -%} - \ No newline at end of file diff --git a/src/content/testing/code-debugging.md b/src/content/testing/code-debugging.md index 6b264d32ea7..b83a568161b 100644 --- a/src/content/testing/code-debugging.md +++ b/src/content/testing/code-debugging.md @@ -33,7 +33,7 @@ behavior of your application. You can view your logs in DevTools' * [`log()`][]: Includes greater granularity and more information in the logging output. Part of the `dart:developer` library. -* [`debugPrint()`][]: If too much output results in discarded log lines, use +* [`debugPrint()`][]: If too much output results in discarded log lines, use this to keep those lines. Will print messages in release mode unless part of a debug mode check or an assert. Part of the `foundations` library. @@ -184,7 +184,7 @@ the root of the widget tree. It returns a "flattened" tree.
    Expand to view the widget tree for Example 4 -{% render docs/testing/trees/widget-tree.md -%} +{% render "docs/testing/trees/widget-tree.md" -%}
    @@ -254,7 +254,7 @@ The constraints flow down the tree and the sizes flow back up.
    Expand to view the render tree for Example 5 -{% render docs/testing/trees/render-tree.md -%} +{% render "docs/testing/trees/render-tree.md" -%}
    @@ -352,7 +352,7 @@ class AppHome extends StatelessWidget {
    Expand to view the output of layer tree for Example 6 -{% render docs/testing/trees/layer-tree.md -%} +{% render "docs/testing/trees/layer-tree.md" -%}
    @@ -443,7 +443,7 @@ class AppHome extends StatelessWidget {
    Expand to view the focus tree for Example 7 -{% render docs/testing/trees/focus-tree.md -%} +{% render "docs/testing/trees/focus-tree.md" -%}
    @@ -500,7 +500,7 @@ class AppHome extends StatelessWidget {
    Expand to view the semantic tree for Example 8 -{% render docs/testing/trees/semantic-tree.md -%} +{% render "docs/testing/trees/semantic-tree.md" -%}
    diff --git a/src/content/testing/common-errors.md b/src/content/testing/common-errors.md index 4c91237c9a6..17d0ae11b2e 100644 --- a/src/content/testing/common-errors.md +++ b/src/content/testing/common-errors.md @@ -500,7 +500,7 @@ For more information and to learn how to fix, check out the following video on [`PrimaryScrollController`][controller-video]: -{% ytEmbed '33_0ABjFJUU', 'PrimaryScrollController | Decoding Flutter' %} + [controller-video]: {{site.api}}/flutter/widgets/PrimaryScrollController-class.html diff --git a/src/content/testing/integration-tests/index.md b/src/content/testing/integration-tests/index.md index 481c35a0c0c..ea0aeea5e1e 100644 --- a/src/content/testing/integration-tests/index.md +++ b/src/content/testing/integration-tests/index.md @@ -139,9 +139,9 @@ Output: ```console Building flutter tool... -Resolving dependencies... +Resolving dependencies... Got dependencies. -Resolving dependencies... +Resolving dependencies... + file 7.0.0 + flutter_driver 0.0.0 from sdk flutter + fuchsia_remote_debug_protocol 0.0.0 from sdk flutter @@ -171,7 +171,7 @@ dev_dependencies: ## Create the integration test files -Integration tests reside in a separate directory inside +Integration tests reside in a separate directory inside your Flutter project. 1. Create a new directory named `integration_test`. @@ -306,23 +306,23 @@ complete the following tasks. Based on platform, the command result should resemble the following output. -{% tabs %} -{% tab "Windows" %} + + -{% render docs/test/integration/windows-example.md %} +{% render "docs/test/integration/windows-example.md" %} -{% endtab %} -{% tab "macOS" %} + + -{% render docs/test/integration/macos-example.md %} +{% render "docs/test/integration/macos-example.md" %} -{% endtab %} -{% tab "Linux" %} + + -{% render docs/test/integration/linux-example.md %} +{% render "docs/test/integration/linux-example.md" %} -{% endtab %} -{% endtabs %} + + --- diff --git a/src/content/testing/native-debugging.md b/src/content/testing/native-debugging.md index bca641e288b..a9f0cb69327 100644 --- a/src/content/testing/native-debugging.md +++ b/src/content/testing/native-debugging.md @@ -51,7 +51,7 @@ debugging your own Flutter project as well. ```console Creating project my_app... - Resolving dependencies in my_app... + Resolving dependencies in my_app... Got dependencies in my_app. Wrote 129 files. @@ -118,7 +118,7 @@ debugging your own Flutter project as well. - In the **Editor Groups**: - The highlighted breakpoint in `main.dart` - The widget hierarchy for the Flutter app - in the **Widget Tree** of the **Widget Inspector** + in the **Widget Tree** of the **Widget Inspector** - In the **side bar**: - The state of the app in the **Call Stack** section - The value of the `this` local variable in the **Variables** section @@ -172,15 +172,15 @@ You can step in, out, and over Dart statements, hot reload, or resume the app. | Icon | Action | Default keyboard shortcut | |-----------------------------------------------------|-----------------------|-------------------------------------------------------| -| {% render docs/vscode-flutter-bar/play.md %} | Start or Resume | F5 | -| {% render docs/vscode-flutter-bar/pause.md %} | Pause | F6 | -| {% render docs/vscode-flutter-bar/step-over.md %} | Step Over | F10 | -| {% render docs/vscode-flutter-bar/step-into.md %} | Step Into | F11 | -| {% render docs/vscode-flutter-bar/step-out.md %} | Step Out | Shift + F11 | -| {% render docs/vscode-flutter-bar/hot-reload.md %} | Hot Reload | Ctrl + F5 | -| {% render docs/vscode-flutter-bar/hot-restart.md %} | Hot Restart | Shift + Special + F5 | -| {% render docs/vscode-flutter-bar/stop.md %} | Stop | Shift + F5 | -| {% render docs/vscode-flutter-bar/inspector.md %} | Open Widget Inspector | | +| {% render "docs/vscode-flutter-bar/play.md" %} | Start or Resume | F5 | +| {% render "docs/vscode-flutter-bar/pause.md" %} | Pause | F6 | +| {% render "docs/vscode-flutter-bar/step-over.md" %} | Step Over | F10 | +| {% render "docs/vscode-flutter-bar/step-into.md" %} | Step Into | F11 | +| {% render "docs/vscode-flutter-bar/step-out.md" %} | Step Out | Shift + F11 | +| {% render "docs/vscode-flutter-bar/hot-reload.md" %} | Hot Reload | Ctrl + F5 | +| {% render "docs/vscode-flutter-bar/hot-restart.md" %} | Hot Restart | Shift + Special + F5 | +| {% render "docs/vscode-flutter-bar/stop.md" %} | Stop | Shift + F5 | +| {% render "docs/vscode-flutter-bar/inspector.md" %} | Open Widget Inspector | | {:.table .table-striped} @@ -312,7 +312,7 @@ test Flutter app. This update adds native code to debug. ``` ```console - Resolving dependencies... + Resolving dependencies... collection 1.17.1 (1.17.2 available) + flutter_web_plugins 0.0.0 from sdk flutter matcher 0.12.15 (0.12.16 available) @@ -338,7 +338,7 @@ test Flutter app. This update adds native code to debug. 1. In Linux or macOS, run this `find` command. ```console - $ find ./ -mmin -120 + $ find ./ -mmin -120 ``` ```console @@ -356,11 +356,11 @@ test Flutter app. This update adds native code to debug. ``` 1. In Windows, run this command in the command prompt. - ```powershell + ```ps Get-ChildItem C:\dev\example\ -Rescurse | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} ``` - ```powershell + ```ps C:\dev\example\ios\Flutter\ @@ -425,7 +425,7 @@ with the Xcode and Visual Studio guides. These section uses the same example Flutter `url_launcher` app created in [Update test Flutter app](#update-test-flutter-app). -{% render docs/debug/debug-flow-android.md %} +{% render "docs/debug/debug-flow-android.md" %} ### Debug Dart and iOS code using Xcode @@ -436,7 +436,7 @@ Flutter via VS Code and Xcode. You need to run both VS Code and Xcode. These section uses the same example Flutter `url_launcher` app created in [Update test Flutter app](#update-test-flutter-app). -{% render docs/debug/debug-flow-ios.md %} +{% render "docs/debug/debug-flow-ios.md" %} ### Debug Dart and macOS code using Xcode @@ -447,7 +447,7 @@ Flutter via VS Code and Xcode. You need to run both VS Code and Xcode. These section uses the same example Flutter `url_launcher` app created in [Update test Flutter app](#update-test-flutter-app). -{% render docs/debug/debug-flow-macos.md %} +{% render "docs/debug/debug-flow-macos.md" %} ### Debug Dart and C++ code using Visual Studio @@ -459,7 +459,7 @@ You need to run both VS Code and Visual Studio. These section uses the same example Flutter `url_launcher` app created in [Update test Flutter app](#update-test-flutter-app). -{% render docs/debug/debug-flow-windows.md %} +{% render "docs/debug/debug-flow-windows.md" %} ## Resources diff --git a/src/content/testing/overview.md b/src/content/testing/overview.md index 9420016694f..05fbcea8d06 100644 --- a/src/content/testing/overview.md +++ b/src/content/testing/overview.md @@ -1,6 +1,6 @@ --- title: Testing Flutter apps -description: +description: >- Learn more about the different types of testing and how to write them. --- @@ -63,7 +63,8 @@ check out [Testing plugins][]. ### Recipes {:.no_toc} -{% include docs/testing-toc.md type='unit' %} +- [Introduction to unit testing](/cookbook/testing/unit/introduction) +- [Mock dependencies using Mockito](/cookbook/testing/unit/mocking) ## Widget tests @@ -81,7 +82,11 @@ an implementation much simpler than a full-blown UI system. ### Recipes {:.no_toc} -{% include docs/testing-toc.md type='widget' %} +- [Introduction to widget testing](/cookbook/testing/widget/introduction) +- [Find widgets using finders](/cookbook/testing/widget/finders) +- [Handling scrolling in widget tests](/cookbook/testing/widget/scrolling) +- [Tap, drag, and enter text in widget tests](/cookbook/testing/widget/tap-drag) +- [Test different orientations](/cookbook/testing/widget/orientation) ## Integration tests @@ -101,7 +106,8 @@ testing page][]. ### Recipes {:.no_toc} -{% include docs/testing-toc.md type='integration' %} +- [Integration testing concepts](/cookbook/testing/integration/introduction) +- [Measure performance with an integration test](/cookbook/testing/integration/profiling) ## Continuous integration services diff --git a/src/content/tools/android-studio.md b/src/content/tools/android-studio.md index 88503f4c0bc..aaf249078f7 100644 --- a/src/content/tools/android-studio.md +++ b/src/content/tools/android-studio.md @@ -33,9 +33,9 @@ To install the latest version of the following IDEs, follow their instructions: ### Install the Flutter plugin {: #install-plugin} -{% tabs "dev-os" %} + -{% tab "Windows" %} + 1. Go to **File** > **Settings**. @@ -59,8 +59,8 @@ To install the latest version of the following IDEs, follow their instructions: 1. Click **Restart** when prompted. -{% endtab %} -{% tab "macOS" %} + + 1. Start Android Studio or IntelliJ. @@ -85,8 +85,8 @@ To install the latest version of the following IDEs, follow their instructions: 1. Click **Restart** when prompted. -{% endtab %} -{% tab "Linux" %} + + 1. Go to **File** > **Settings**. @@ -110,9 +110,9 @@ To install the latest version of the following IDEs, follow their instructions: 1. Click **Restart** when prompted. -{% endtab %} + -{% endtabs %} + ### Updating the plugins {:#updating} @@ -139,7 +139,7 @@ differs between Android Studio and IntelliJ. 1. In the IDE, click **New Flutter Project** from the **Welcome** window or **File > New > New Flutter Project** from the main IDE window. 1. Specify the **Flutter SDK path** and click **Next**. - 1. Enter your desired **Project name**, + 1. Enter your desired **Project name**, **Description**, and **Project location**. 1. If you might publish this app, [set the company domain](#set-the-company-domain). @@ -172,7 +172,7 @@ is released. Your organization name should be unique. To open an existing Flutter project: 1. In the IDE, click **Open** from the **Welcome** window, or - **File > Open** from the main IDE window. + **File > Open** from the main IDE window. 1. Browse to the directory holding your existing Flutter source code files. 1. Click **Open**. diff --git a/src/content/tools/devtools/extensions.md b/src/content/tools/devtools/extensions.md index 6e5ebc504b9..5f3c88b54db 100644 --- a/src/content/tools/devtools/extensions.md +++ b/src/content/tools/devtools/extensions.md @@ -80,6 +80,6 @@ a free article on Medium. To learn more about writing and using DevTools extensions, check out the following video: -{% ytEmbed 'gOrSc4s4RWY', 'Building DevTools extensions | Flutter Build Show' %} + [article]: {{site.flutter-medium}}/dart-flutter-devtools-extensions-c8bc1aaf8e5f diff --git a/src/content/tools/devtools/index.md b/src/content/tools/devtools/index.md index 76895491ede..0241dc53853 100644 --- a/src/content/tools/devtools/index.md +++ b/src/content/tools/devtools/index.md @@ -1,5 +1,6 @@ --- title: Flutter and Dart DevTools +breadcrumb: DevTools description: How to use Flutter DevTools with Flutter. --- @@ -15,7 +16,7 @@ same set of tools. For a video introduction to DevTools, check out the following deep dive and use-case walkthrough: -{% ytEmbed '_EYk-E29edo', 'Dive in to Flutter and Dart DevTools' %} + ## What can I do with DevTools? diff --git a/src/content/tools/devtools/legacy-inspector.md b/src/content/tools/devtools/legacy-inspector.md index 0fe94d448d6..f807867b443 100644 --- a/src/content/tools/devtools/legacy-inspector.md +++ b/src/content/tools/devtools/legacy-inspector.md @@ -80,7 +80,7 @@ Flutter layouts. For an overview of what you can do with this tool, see the Flutter Explorer video: -{% ytEmbed 'Jakrc3Tn_y4', 'DevTools Layout Explorer' %} + You might also find the following step-by-step article useful: diff --git a/src/content/tools/devtools/release-notes/index.md b/src/content/tools/devtools/release-notes/index.md index c860c3079f2..b7816164f74 100644 --- a/src/content/tools/devtools/release-notes/index.md +++ b/src/content/tools/devtools/release-notes/index.md @@ -1,5 +1,6 @@ --- title: DevTools release notes +breadcrumb: Release notes description: Learn about the latest changes in Dart and Flutter DevTools. showToc: false --- @@ -20,12 +21,8 @@ $ dart devtools --version {% comment %} When adding the release notes for a new DevTools release, -make sure to add the version number as an entry to the list -found at `/src/_data/devtools_releases.yml`. +make sure to add the version number as the first entry in the list +found at `/site/src/data/devtools_releases.dart`. {% endcomment -%} -{% assign releases = devtools_releases.releases %} - -{% for release in releases -%} -* [{{release}} release notes](/tools/devtools/release-notes/release-notes-{{release}}) -{% endfor -%} + diff --git a/src/content/tools/devtools/release-notes/release-notes-2.10.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.10.0-src.md deleted file mode 100644 index aca64c88103..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.10.0-src.md +++ /dev/null @@ -1,42 +0,0 @@ -# DevTools 2.10.0 release notes - -The 2.10.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## Flutter inspector updates - -* Added search support to the Widget Tree, and - added a breadcrumb navigator to the Widget Details Tree to - allow for quickly navigating through the tree hierarchy - - [#3525](https://github.com/flutter/devtools/pull/3525) - - ![inspector search](/assets/images/docs/tools/devtools/release-notes/images-2.10.0/image1.png "inspector_search") - -## CPU profiler updates - -* Fix a null reference in the CPU profiler - when loading an offline snapshot - - [#3596](https://github.com/flutter/devtools/pull/3596) - -## Debugger updates - -* Added support for multi-token file search, and - improved search match prioritization to - rank file name matches over full path matches - - [#3582](https://github.com/flutter/devtools/pull/3582) -* Fix some focus-related issues - - [#3602](https://github.com/flutter/devtools/pull/3602) - -## Logging view updates - -* Fix a fatal error that occurred when - filtering logs more than once - - [#3588](https://github.com/flutter/devtools/pull/3588) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.9.2...v2.10.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.10.0.md b/src/content/tools/devtools/release-notes/release-notes-2.10.0.md index 6dbd49ad0a8..171a03f85df 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.10.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.10.0.md @@ -1,7 +1,48 @@ --- +title: DevTools 2.10.0 release notes shortTitle: 2.10.0 release notes +breadcrumb: 2.10.0 description: Release notes for Dart and Flutter DevTools version 2.10.0. showToc: false --- -{% include ./release-notes-2.10.0-src.md %} +The 2.10.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## Flutter inspector updates + +* Added search support to the Widget Tree, and + added a breadcrumb navigator to the Widget Details Tree to + allow for quickly navigating through the tree hierarchy - + [#3525](https://github.com/flutter/devtools/pull/3525) + + ![inspector search](/assets/images/docs/tools/devtools/release-notes/images-2.10.0/image1.png "inspector_search") + +## CPU profiler updates + +* Fix a null reference in the CPU profiler + when loading an offline snapshot - + [#3596](https://github.com/flutter/devtools/pull/3596) + +## Debugger updates + +* Added support for multi-token file search, and + improved search match prioritization to + rank file name matches over full path matches - + [#3582](https://github.com/flutter/devtools/pull/3582) +* Fix some focus-related issues - + [#3602](https://github.com/flutter/devtools/pull/3602) + +## Logging view updates + +* Fix a fatal error that occurred when + filtering logs more than once - + [#3588](https://github.com/flutter/devtools/pull/3588) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.9.2...v2.10.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.11.2-src.md b/src/content/tools/devtools/release-notes/release-notes-2.11.2-src.md deleted file mode 100644 index 209412d12fe..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.11.2-src.md +++ /dev/null @@ -1,35 +0,0 @@ -# DevTools 2.11.2 release notes - -The 2.11.2 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* This release included a lot of cleanup and reduction in technical debt. - -## CPU profiler updates - -* Added the source line number to file uris in CPU profiles - - [#3718](https://github.com/flutter/devtools/pull/3718) - - ![cpu stack frame line numbers](/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image1.png "cpu stack frame line numbers") - -## Debugger updates - -* File opener UX improvements, including support for clicking - the source file name to open the file search window - - [#3612](https://github.com/flutter/devtools/pull/3612), - [#3758](https://github.com/flutter/devtools/pull/3758) -* Added support for auto-scrolling the File Explorer to the selected file - - [#3786](https://github.com/flutter/devtools/pull/3786), - [#3794](https://github.com/flutter/devtools/pull/3794) - - ![debugger file explorer scrolling](/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image2.gif "debugger file explorer scrolling") - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.10.0...v2.11.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.11.2.md b/src/content/tools/devtools/release-notes/release-notes-2.11.2.md index 84c403d4065..dde3af4b0ab 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.11.2.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.11.2.md @@ -1,7 +1,41 @@ --- +title: DevTools 2.11.2 release notes shortTitle: 2.11.2 release notes +breadcrumb: 2.11.2 description: Release notes for Dart and Flutter DevTools version 2.11.2. showToc: false --- -{% include ./release-notes-2.11.2-src.md %} +The 2.11.2 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* This release included a lot of cleanup and reduction in technical debt. + +## CPU profiler updates + +* Added the source line number to file uris in CPU profiles - + [#3718](https://github.com/flutter/devtools/pull/3718) + + ![cpu stack frame line numbers](/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image1.png "cpu stack frame line numbers") + +## Debugger updates + +* File opener UX improvements, including support for clicking + the source file name to open the file search window - + [#3612](https://github.com/flutter/devtools/pull/3612), + [#3758](https://github.com/flutter/devtools/pull/3758) +* Added support for auto-scrolling the File Explorer to the selected file - + [#3786](https://github.com/flutter/devtools/pull/3786), + [#3794](https://github.com/flutter/devtools/pull/3794) + + ![debugger file explorer scrolling](/assets/images/docs/tools/devtools/release-notes/images-2.11.2/image2.gif "debugger file explorer scrolling") + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.10.0...v2.11.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.12.1-src.md b/src/content/tools/devtools/release-notes/release-notes-2.12.1-src.md deleted file mode 100644 index f78639d08b6..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.12.1-src.md +++ /dev/null @@ -1,33 +0,0 @@ -# DevTools 2.12.1 release notes - -The 2.12.1 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* This release included a lot of cleanup and reduction in technical debt. - -## Flutter inspector updates - -* Added scrolling support to hover cards - - [#3923](https://github.com/flutter/devtools/pull/3923) - -## Performance updates - -* Added documentation links to the - "Enhance Tracing" and "More debugging options" menus. - Read the - [enhance tracing documentation](https://docs.flutter.dev/tools/devtools/performance#enhance-tracing) - to learn more about these features - - [#3934](https://github.com/flutter/devtools/pull/3934), - [#3936](https://github.com/flutter/devtools/pull/3936) - - ![enhance tracing documentation links](/assets/images/docs/tools/devtools/release-notes/images-2.12.1/image1.png "enhance tracing documentation links") - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.11.2...v2.12.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.12.1.md b/src/content/tools/devtools/release-notes/release-notes-2.12.1.md index f82a6eb829b..c3c45e12555 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.12.1.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.12.1.md @@ -1,7 +1,39 @@ --- +title: DevTools 2.12.1 release notes shortTitle: 2.12.1 release notes +breadcrumb: 2.12.1 description: Release notes for Dart and Flutter DevTools version 2.12.1. showToc: false --- -{% include ./release-notes-2.12.1-src.md %} +The 2.12.1 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* This release included a lot of cleanup and reduction in technical debt. + +## Flutter inspector updates + +* Added scrolling support to hover cards - + [#3923](https://github.com/flutter/devtools/pull/3923) + +## Performance updates + +* Added documentation links to the + "Enhance Tracing" and "More debugging options" menus. + Read the + [enhance tracing documentation](https://docs.flutter.dev/tools/devtools/performance#enhance-tracing) + to learn more about these features - + [#3934](https://github.com/flutter/devtools/pull/3934), + [#3936](https://github.com/flutter/devtools/pull/3936) + + ![enhance tracing documentation links](/assets/images/docs/tools/devtools/release-notes/images-2.12.1/image1.png "enhance tracing documentation links") + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.11.2...v2.12.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.12.2-src.md b/src/content/tools/devtools/release-notes/release-notes-2.12.2-src.md deleted file mode 100644 index eab8b1fd1bf..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.12.2-src.md +++ /dev/null @@ -1,17 +0,0 @@ -# DevTools 2.12.2 release notes - -The 2.12.2 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Recover from missing trace events - - [#3960](https://github.com/flutter/devtools/pull/3960) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.12.1...v2.12.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.12.2.md b/src/content/tools/devtools/release-notes/release-notes-2.12.2.md index f5dea7f1a0b..4ec5c962e6b 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.12.2.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.12.2.md @@ -1,7 +1,23 @@ --- +title: DevTools 2.12.2 release notes shortTitle: 2.12.2 release notes +breadcrumb: 2.12.2 description: Release notes for Dart and Flutter DevTools version 2.12.2. showToc: false --- -{% include ./release-notes-2.12.2-src.md %} +The 2.12.2 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Recover from missing trace events - + [#3960](https://github.com/flutter/devtools/pull/3960) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.12.1...v2.12.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.13.1-src.md b/src/content/tools/devtools/release-notes/release-notes-2.13.1-src.md deleted file mode 100644 index 89f6a124d72..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.13.1-src.md +++ /dev/null @@ -1,57 +0,0 @@ -# DevTools 2.13.1 release notes - -The 2.13.1 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* This release included a lot of cleanup and reduction in technical debt. - The most notable is the completion of our migration to sound null safety. -* Show release notes in IDE embedded versions of DevTools - - [#4053](https://github.com/flutter/devtools/pull/4053) -* Polish to the DevTools footer - - [#3989](https://github.com/flutter/devtools/pull/3989), - [#4026](https://github.com/flutter/devtools/pull/4026), - [#4041](https://github.com/flutter/devtools/pull/4041), - [#4076](https://github.com/flutter/devtools/pull/4076) - -## Performance updates - -* Added a new feature to help you debug raster jank in your Flutter app. - This feature allows you to take a snapshot of the - current screen shown in your app, and then - break down rendering time for that scene by layer. - This can help you identify parts of a scene that are expensive to rasterize - - [#4046](https://github.com/flutter/devtools/pull/4046) - - ![raster-metrics-feature](/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image1.png "raster metrics feature") - -* Added a scope setting for "Track Widget Builds", allowing - you to specify whether widget builds should be tracked in - your code only or in all code - - [#4010](https://github.com/flutter/devtools/pull/4010) - - ![track-widget-builds-scope-setting](/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image2.png "track widget builds scope setting") - -## CPU profiler updates - -* Use package uris instead of file uris in the CPU profiler "Source" column - - [#3932](https://github.com/flutter/devtools/pull/3932) - -## Debugger updates - -* Fix scrolling bug with debugger breakpoints - - [#4074](https://github.com/flutter/devtools/pull/4074) - -## Flutter inspector updates - -* Add support for displaying flex values larger than 5 in the Layout Explorer - - [#4055](https://github.com/flutter/devtools/pull/4055) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.12.2...v2.13.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.13.1.md b/src/content/tools/devtools/release-notes/release-notes-2.13.1.md index df42b17612d..b7fc73fd770 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.13.1.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.13.1.md @@ -1,7 +1,63 @@ --- +title: DevTools 2.13.1 release notes shortTitle: 2.13.1 release notes +breadcrumb: 2.13.1 description: Release notes for Dart and Flutter DevTools version 2.13.1. showToc: false --- -{% include ./release-notes-2.13.1-src.md %} +The 2.13.1 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* This release included a lot of cleanup and reduction in technical debt. + The most notable is the completion of our migration to sound null safety. +* Show release notes in IDE embedded versions of DevTools - + [#4053](https://github.com/flutter/devtools/pull/4053) +* Polish to the DevTools footer - + [#3989](https://github.com/flutter/devtools/pull/3989), + [#4026](https://github.com/flutter/devtools/pull/4026), + [#4041](https://github.com/flutter/devtools/pull/4041), + [#4076](https://github.com/flutter/devtools/pull/4076) + +## Performance updates + +* Added a new feature to help you debug raster jank in your Flutter app. + This feature allows you to take a snapshot of the + current screen shown in your app, and then + break down rendering time for that scene by layer. + This can help you identify parts of a scene that are expensive to rasterize - + [#4046](https://github.com/flutter/devtools/pull/4046) + + ![raster-metrics-feature](/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image1.png "raster metrics feature") + +* Added a scope setting for "Track Widget Builds", allowing + you to specify whether widget builds should be tracked in + your code only or in all code - + [#4010](https://github.com/flutter/devtools/pull/4010) + + ![track-widget-builds-scope-setting](/assets/images/docs/tools/devtools/release-notes/images-2.13.1/image2.png "track widget builds scope setting") + +## CPU profiler updates + +* Use package uris instead of file uris in the CPU profiler "Source" column - + [#3932](https://github.com/flutter/devtools/pull/3932) + +## Debugger updates + +* Fix scrolling bug with debugger breakpoints - + [#4074](https://github.com/flutter/devtools/pull/4074) + +## Flutter inspector updates + +* Add support for displaying flex values larger than 5 in the Layout Explorer - + [#4055](https://github.com/flutter/devtools/pull/4055) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.12.2...v2.13.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.14.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.14.0-src.md deleted file mode 100644 index 9ce0aa6deb4..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.14.0-src.md +++ /dev/null @@ -1,63 +0,0 @@ -# DevTools 2.14.0 release notes - -The 2.14.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Added a link to the new DevTools - [Discord channel](https://discord.com/channels/608014603317936148/958862085297672282) - in the About DevTools dialog - - [#4102](https://github.com/flutter/devtools/pull/4102) - - ![about-devtools](/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image1.png "about devtools") - -## Network updates - -* Added "Copy as URL" and "Copy as cURL" actions for - selected requests in the network profiler - (special thanks to [@jankuss](https://github.com/jankuss)!) - - [#4113](https://github.com/flutter/devtools/pull/4113) - - ![network-request-copy-actions](/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image2.png "network request copy actions") - -## Flutter inspector updates - -* Added a setting to control whether hovering over a widget - in the inspector displays its properties and values in a hover card - - [#4090](https://github.com/flutter/devtools/pull/4090) - -## Debugger updates - -* Added auto complete suggestions in the console - (special thanks to [@jankuss](https://github.com/jankuss)!) - - [#4062](https://github.com/flutter/devtools/pull/4062) - - ![auto-complete-suggestions](/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image3.png "auto complete suggestions") - -* Added the option to copy the full file path for a selected library - - [#4147](https://github.com/flutter/devtools/pull/4147) -* Fixed formatting in the debugger exception menu - - [#4066](https://github.com/flutter/devtools/pull/4066) - -## Memory updates - -* Fixed formatting for memory values in the heap tree view - - [#4153](https://github.com/flutter/devtools/pull/4153) -* Fixed a bug that was preventing GC events from - showing up in the memory chart - - [#4131](https://github.com/flutter/devtools/pull/4131) - -## Performance updates - -* Warn users that the rendering layer toggles in the - "More Debugging Options" menu are not available for profile mode apps - - [#4075](https://github.com/flutter/devtools/pull/4075) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.13.1...v2.14.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.14.0.md b/src/content/tools/devtools/release-notes/release-notes-2.14.0.md index e42036e8c78..74f50650f73 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.14.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.14.0.md @@ -1,7 +1,69 @@ --- +title: DevTools 2.14.0 release notes shortTitle: 2.14.0 release notes +breadcrumb: 2.14.0 description: Release notes for Dart and Flutter DevTools version 2.14.0. showToc: false --- -{% include ./release-notes-2.14.0-src.md %} +The 2.14.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Added a link to the new DevTools + [Discord channel](https://discord.com/channels/608014603317936148/958862085297672282) + in the About DevTools dialog - + [#4102](https://github.com/flutter/devtools/pull/4102) + + ![about-devtools](/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image1.png "about devtools") + +## Network updates + +* Added "Copy as URL" and "Copy as cURL" actions for + selected requests in the network profiler + (special thanks to [@jankuss](https://github.com/jankuss)!) - + [#4113](https://github.com/flutter/devtools/pull/4113) + + ![network-request-copy-actions](/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image2.png "network request copy actions") + +## Flutter inspector updates + +* Added a setting to control whether hovering over a widget + in the inspector displays its properties and values in a hover card - + [#4090](https://github.com/flutter/devtools/pull/4090) + +## Debugger updates + +* Added auto complete suggestions in the console + (special thanks to [@jankuss](https://github.com/jankuss)!) - + [#4062](https://github.com/flutter/devtools/pull/4062) + + ![auto-complete-suggestions](/assets/images/docs/tools/devtools/release-notes/images-2.14.0/image3.png "auto complete suggestions") + +* Added the option to copy the full file path for a selected library - + [#4147](https://github.com/flutter/devtools/pull/4147) +* Fixed formatting in the debugger exception menu - + [#4066](https://github.com/flutter/devtools/pull/4066) + +## Memory updates + +* Fixed formatting for memory values in the heap tree view - + [#4153](https://github.com/flutter/devtools/pull/4153) +* Fixed a bug that was preventing GC events from + showing up in the memory chart - + [#4131](https://github.com/flutter/devtools/pull/4131) + +## Performance updates + +* Warn users that the rendering layer toggles in the + "More Debugging Options" menu are not available for profile mode apps - + [#4075](https://github.com/flutter/devtools/pull/4075) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.13.1...v2.14.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.15.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.15.0-src.md deleted file mode 100644 index dd70b3b4423..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.15.0-src.md +++ /dev/null @@ -1,50 +0,0 @@ -# DevTools 2.15.0 release notes - -The 2.15.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* The DevTools 2.15 release includes improvements to all tables in - DevTools (logging view, network profiler, CPU profiler, and so on) - - [#4175](https://github.com/flutter/devtools/pull/4175) - -## Performance updates - -* Added outlines to each layer displayed in the Raster Metrics tool - - [#4192](https://github.com/flutter/devtools/pull/4192) - - ![raster-metrics-layer-outlines](/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image1.png "raster metrics layer outlines") - -* Fix a bug with loading offline data - - [#4189](https://github.com/flutter/devtools/pull/4189) - -## Network updates - -* Added a Json viewer with syntax highlighting for network responses - - [#4167](https://github.com/flutter/devtools/pull/4167) - - ![network-response-json-viewer](/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image2.png "network response json viewer") - -* Added the ability to copy network responses - - [#4190](https://github.com/flutter/devtools/pull/4190) - -## Memory updates - -* Added the ability to select a different isolate from the DevTools footer - - [#4173](https://github.com/flutter/devtools/pull/4173) -* Made the automatic snapshotting feature a configurable setting - - [#4200](https://github.com/flutter/devtools/pull/4200) - -## CPU profiler - -* Stop manually truncating source URIs in the profiler tables - - [#4166](https://github.com/flutter/devtools/pull/4166) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.14.0...v2.15.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.15.0.md b/src/content/tools/devtools/release-notes/release-notes-2.15.0.md index 13088591b67..fc80e197c84 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.15.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.15.0.md @@ -1,7 +1,56 @@ --- +title: DevTools 2.15.0 release notes shortTitle: 2.15.0 release notes +breadcrumb: 2.15.0 description: Release notes for Dart and Flutter DevTools version 2.15.0. showToc: false --- -{% include ./release-notes-2.15.0-src.md %} +The 2.15.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* The DevTools 2.15 release includes improvements to all tables in + DevTools (logging view, network profiler, CPU profiler, and so on) - + [#4175](https://github.com/flutter/devtools/pull/4175) + +## Performance updates + +* Added outlines to each layer displayed in the Raster Metrics tool - + [#4192](https://github.com/flutter/devtools/pull/4192) + + ![raster-metrics-layer-outlines](/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image1.png "raster metrics layer outlines") + +* Fix a bug with loading offline data - + [#4189](https://github.com/flutter/devtools/pull/4189) + +## Network updates + +* Added a Json viewer with syntax highlighting for network responses - + [#4167](https://github.com/flutter/devtools/pull/4167) + + ![network-response-json-viewer](/assets/images/docs/tools/devtools/release-notes/images-2.15.0/image2.png "network response json viewer") + +* Added the ability to copy network responses - + [#4190](https://github.com/flutter/devtools/pull/4190) + +## Memory updates + +* Added the ability to select a different isolate from the DevTools footer - + [#4173](https://github.com/flutter/devtools/pull/4173) +* Made the automatic snapshotting feature a configurable setting - + [#4200](https://github.com/flutter/devtools/pull/4200) + +## CPU profiler + +* Stop manually truncating source URIs in the profiler tables - + [#4166](https://github.com/flutter/devtools/pull/4166) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.14.0...v2.15.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.16.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.16.0-src.md deleted file mode 100644 index a60520d2a44..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.16.0-src.md +++ /dev/null @@ -1,17 +0,0 @@ -# DevTools 2.16.0 release notes - -The 2.16.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -This release includes several bug fixes and improvements, as well as -work towards some new features that are coming soon! - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.15.0...v2.16.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.16.0.md b/src/content/tools/devtools/release-notes/release-notes-2.16.0.md index c2f93662af7..0cb438f979d 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.16.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.16.0.md @@ -1,7 +1,23 @@ --- +title: DevTools 2.16.0 release notes shortTitle: 2.16.0 release notes +breadcrumb: 2.16.0 description: Release notes for Dart and Flutter DevTools version 2.16.0. showToc: false --- -{% include ./release-notes-2.16.0-src.md %} +The 2.16.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +This release includes several bug fixes and improvements, as well as +work towards some new features that are coming soon! + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.15.0...v2.16.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.17.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.17.0-src.md deleted file mode 100644 index 94975be874e..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.17.0-src.md +++ /dev/null @@ -1,44 +0,0 @@ -# DevTools 2.17.0 release notes - -The 2.17.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## Inspector updates - -* Added support for manually setting the package directories for your app. - If you've ever loaded the Inspector and noticed that - some of your widgets aren't present in the widget tree, this might - indicate that the package directories for your app - haven't been set or detected properly. - Your package directories determine which widgets - the Inspector considers to be from _your_ application. - If you see an empty Inspector widget tree, - or if you develop widgets across multiple packages, - and want widgets from all these locations to show up in your tree, - check the **Inspector Settings** dialog to ensure that your package - directories are properly configured - - [#4306](https://github.com/flutter/devtools/pull/4306) - - ![frame_analysis](/assets/images/docs/tools/devtools/release-notes/images-2.17.0/package_directories.png "package directories") - -## Performance updates - -* Added a **Frame Analysis** tab to the Performance page. - When analyzing a janky Flutter frame, - this view provides hints for how to diagnose the jank and - detects expensive operations that might have - contributed to the slow frame time. - This view also shows a breakdown of your Flutter frame time - per phase (**Build**, **Layout**, **Paint**, and **Raster**) - to try to guide you in the right direction - - [#4339](https://github.com/flutter/devtools/pull/4339) - - ![frame_analysis](/assets/images/docs/tools/devtools/release-notes/images-2.17.0/frame_analysis.png "frame analysis") - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.16.0...v2.17.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.17.0.md b/src/content/tools/devtools/release-notes/release-notes-2.17.0.md index 1d9a40bb533..a0be4011918 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.17.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.17.0.md @@ -1,7 +1,50 @@ --- +title: DevTools 2.17.0 release notes shortTitle: 2.17.0 release notes +breadcrumb: 2.17.0 description: Release notes for Dart and Flutter DevTools version 2.17.0. showToc: false --- -{% include ./release-notes-2.17.0-src.md %} +The 2.17.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## Inspector updates + +* Added support for manually setting the package directories for your app. + If you've ever loaded the Inspector and noticed that + some of your widgets aren't present in the widget tree, this might + indicate that the package directories for your app + haven't been set or detected properly. + Your package directories determine which widgets + the Inspector considers to be from _your_ application. + If you see an empty Inspector widget tree, + or if you develop widgets across multiple packages, + and want widgets from all these locations to show up in your tree, + check the **Inspector Settings** dialog to ensure that your package + directories are properly configured - + [#4306](https://github.com/flutter/devtools/pull/4306) + + ![frame_analysis](/assets/images/docs/tools/devtools/release-notes/images-2.17.0/package_directories.png "package directories") + +## Performance updates + +* Added a **Frame Analysis** tab to the Performance page. + When analyzing a janky Flutter frame, + this view provides hints for how to diagnose the jank and + detects expensive operations that might have + contributed to the slow frame time. + This view also shows a breakdown of your Flutter frame time + per phase (**Build**, **Layout**, **Paint**, and **Raster**) + to try to guide you in the right direction - + [#4339](https://github.com/flutter/devtools/pull/4339) + + ![frame_analysis](/assets/images/docs/tools/devtools/release-notes/images-2.17.0/frame_analysis.png "frame analysis") + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.16.0...v2.17.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.18.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.18.0-src.md deleted file mode 100644 index 6283f2952bf..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.18.0-src.md +++ /dev/null @@ -1,73 +0,0 @@ -# DevTools 2.18.0 release notes - -The 2.18.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## Inspector updates - -- Auto scrolling behavior improved when snapping a widget into focus - - [#4283](https://github.com/flutter/devtools/pull/4283) -- Fix issue where widget inspector wouldn't load when - connecting to a paused app - - [#4527](https://github.com/flutter/devtools/pull/4527) -- Improve widget inspector hover cards to show progress while waiting for data - - [#4488](https://github.com/flutter/devtools/pull/4488) - -## Performance updates - -- Fix issue where scrollbar would go out of sync with the frame content - - [#4503](https://github.com/flutter/devtools/pull/4503) -- Add offline support for raster stats - - [#4491](https://github.com/flutter/devtools/pull/4491) -- Add 'Rendering time' column to Raster Metrics tab - - [#4474](https://github.com/flutter/devtools/pull/4474) - - ![render-time-column](/assets/images/docs/tools/devtools/release-notes/images-2.18.0/render-time-column.png "Rendering time column in the Raster Metrics tab") - -## CPU profiler updates - -- Fix crash when an empty frame is filtered - - [#4502](https://github.com/flutter/devtools/pull/4502) -- Fix bugs in CPU profile trees - - [#4413](https://github.com/flutter/devtools/pull/4413) -- UI Cleanup - [#4404](https://github.com/flutter/devtools/pull/4404) - -## Memory updates - -- Add Profile and Allocation Tracing sub-tabs - - [#4523](https://github.com/flutter/devtools/pull/4523) - - ![profile](/assets/images/docs/tools/devtools/release-notes/images-2.18.0/profile.png "Profile in Memory tab") - - ![allocation-tracing](/assets/images/docs/tools/devtools/release-notes/images-2.18.0/allocation-tracing.png "Allocation Tracing in Memory tab") - -- Implement snapshot visualization - - [#4473](https://github.com/flutter/devtools/pull/4473) - -## Debugger updates - -- Fix bug for file opener and search - - [#4525](https://github.com/flutter/devtools/pull/4525) -- Fix the code view's scrollable area - - [#4448](https://github.com/flutter/devtools/pull/4448) -- Allow syntax highlighting on nested captures in parser - - [#4427](https://github.com/flutter/devtools/pull/4427) - -## Network profiler updates - -- When on the Network tab, network recordings now continue working - after the app hot restarts - - [#4438](https://github.com/flutter/devtools/pull/4438) - -## Logging updates - -- Log messages from non-stdout sources are now shown - - [#4487](https://github.com/flutter/devtools/pull/4487) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.17.0...v2.18.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.18.0.md b/src/content/tools/devtools/release-notes/release-notes-2.18.0.md index 69d21902583..94929845432 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.18.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.18.0.md @@ -1,7 +1,79 @@ --- +title: DevTools 2.18.0 release notes shortTitle: 2.18.0 release notes +breadcrumb: 2.18.0 description: Release notes for Dart and Flutter DevTools version 2.18.0. showToc: false --- -{% include ./release-notes-2.18.0-src.md %} +The 2.18.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## Inspector updates + +- Auto scrolling behavior improved when snapping a widget into focus - + [#4283](https://github.com/flutter/devtools/pull/4283) +- Fix issue where widget inspector wouldn't load when + connecting to a paused app - + [#4527](https://github.com/flutter/devtools/pull/4527) +- Improve widget inspector hover cards to show progress while waiting for data - + [#4488](https://github.com/flutter/devtools/pull/4488) + +## Performance updates + +- Fix issue where scrollbar would go out of sync with the frame content - + [#4503](https://github.com/flutter/devtools/pull/4503) +- Add offline support for raster stats - + [#4491](https://github.com/flutter/devtools/pull/4491) +- Add 'Rendering time' column to Raster Metrics tab - + [#4474](https://github.com/flutter/devtools/pull/4474) + + ![render-time-column](/assets/images/docs/tools/devtools/release-notes/images-2.18.0/render-time-column.png "Rendering time column in the Raster Metrics tab") + +## CPU profiler updates + +- Fix crash when an empty frame is filtered - + [#4502](https://github.com/flutter/devtools/pull/4502) +- Fix bugs in CPU profile trees - + [#4413](https://github.com/flutter/devtools/pull/4413) +- UI Cleanup - [#4404](https://github.com/flutter/devtools/pull/4404) + +## Memory updates + +- Add Profile and Allocation Tracing sub-tabs - + [#4523](https://github.com/flutter/devtools/pull/4523) + + ![profile](/assets/images/docs/tools/devtools/release-notes/images-2.18.0/profile.png "Profile in Memory tab") + + ![allocation-tracing](/assets/images/docs/tools/devtools/release-notes/images-2.18.0/allocation-tracing.png "Allocation Tracing in Memory tab") + +- Implement snapshot visualization - + [#4473](https://github.com/flutter/devtools/pull/4473) + +## Debugger updates + +- Fix bug for file opener and search - + [#4525](https://github.com/flutter/devtools/pull/4525) +- Fix the code view's scrollable area - + [#4448](https://github.com/flutter/devtools/pull/4448) +- Allow syntax highlighting on nested captures in parser - + [#4427](https://github.com/flutter/devtools/pull/4427) + +## Network profiler updates + +- When on the Network tab, network recordings now continue working + after the app hot restarts - + [#4438](https://github.com/flutter/devtools/pull/4438) + +## Logging updates + +- Log messages from non-stdout sources are now shown - + [#4487](https://github.com/flutter/devtools/pull/4487) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.17.0...v2.18.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.19.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.19.0-src.md deleted file mode 100644 index 2fde2870842..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.19.0-src.md +++ /dev/null @@ -1,46 +0,0 @@ -# DevTools 2.19.0 release notes - -The 2.19.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## Performance updates - -* Added a button to toggle the visibility of the Flutter Frames chart - - [#4577](https://github.com/flutter/devtools/pull/4577) - - ![diff](/assets/images/docs/tools/devtools/release-notes/images-2.19.0/4577.png "Flutter Frames") - -* Polish the debug mode warning to better describe which data is - accurate in debug mode and which data may be misleading - - [#3537](https://github.com/flutter/devtools/pull/3537) -* Reorder performance tool tabs and only show the CPU profiler - for the "Timeline Events" tab - - [#4629](https://github.com/flutter/devtools/pull/4629) - -## Memory updates - -* Improvements to the memory Profile tab - - [#4583](https://github.com/flutter/devtools/pull/4583) - -## Debugger updates - -* Fix an issue with hover cards where they were appearing - but never disappearing - - [#4627](https://github.com/flutter/devtools/pull/4627) -* Fix a bug with the file search autocomplete dialog - - [#4409](https://github.com/flutter/devtools/pull/4409) - -## Network profiler updates - -* Added a "Copy" button in the Network Request view - (thanks to @netos23) - - [#4509](https://github.com/flutter/devtools/pull/4509) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.18.0...v2.19.0). - diff --git a/src/content/tools/devtools/release-notes/release-notes-2.19.0.md b/src/content/tools/devtools/release-notes/release-notes-2.19.0.md index 95f90c54844..e65f34b4af4 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.19.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.19.0.md @@ -1,7 +1,51 @@ --- +title: DevTools 2.19.0 release notes shortTitle: 2.19.0 release notes +breadcrumb: 2.19.0 description: Release notes for Dart and Flutter DevTools version 2.19.0. showToc: false --- -{% include ./release-notes-2.19.0-src.md %} +The 2.19.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## Performance updates + +* Added a button to toggle the visibility of the Flutter Frames chart - + [#4577](https://github.com/flutter/devtools/pull/4577) + + ![diff](/assets/images/docs/tools/devtools/release-notes/images-2.19.0/4577.png "Flutter Frames") + +* Polish the debug mode warning to better describe which data is + accurate in debug mode and which data may be misleading - + [#3537](https://github.com/flutter/devtools/pull/3537) +* Reorder performance tool tabs and only show the CPU profiler + for the "Timeline Events" tab - + [#4629](https://github.com/flutter/devtools/pull/4629) + +## Memory updates + +* Improvements to the memory Profile tab - + [#4583](https://github.com/flutter/devtools/pull/4583) + +## Debugger updates + +* Fix an issue with hover cards where they were appearing + but never disappearing - + [#4627](https://github.com/flutter/devtools/pull/4627) +* Fix a bug with the file search autocomplete dialog - + [#4409](https://github.com/flutter/devtools/pull/4409) + +## Network profiler updates + +* Added a "Copy" button in the Network Request view + (thanks to @netos23) - + [#4509](https://github.com/flutter/devtools/pull/4509) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.18.0...v2.19.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.20.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.20.0-src.md deleted file mode 100644 index 485deac8350..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.20.0-src.md +++ /dev/null @@ -1,62 +0,0 @@ -# DevTools 2.20.0 release notes - -The 2.20.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## CPU profiler updates - -* Add support for grouping samples by tag - - [#4693](https://github.com/flutter/devtools/pull/4693) - - ![samples by tag](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4693.png "samples by tag") - -* Enable guidelines for tree view - - [#4722](https://github.com/flutter/devtools/pull/4722) - - ![guidelines](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4722.png "guidelines") - -* Rename "Profile granularity" to "CPU sampling rate" - and move down to the area it relates to - - [#4803](https://github.com/flutter/devtools/pull/4722) - - ![sampling rate](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4803.png "sampling rate") - - -## Memory updates - -* Retire the **Analysis** tab - - [#4714](https://github.com/flutter/devtools/pull/4714) - -* Add a new tab, **Diff**, to enable memory leak detection - and troubleshooting by comparing heap snapshots, - providing insights about the number of instances, - shallow size, retained size, and retaining paths - - [#4714](https://github.com/flutter/devtools/pull/4714) - - ![diff](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4714.png "Diff in Memory tab") - -## Debugger updates - -* Support for inspecting more types of instances in the variables viewer - (Expandos, Types, TypeArguments, Parameters, Closures + closure Contexts, - WeakProperty, Function, FunctionType, ReceivePort, Closure, RegExp) - - [#4760](https://github.com/flutter/devtools/pull/4760) - -* Add support for displaying coverage in CodeView - - [#4700](https://github.com/flutter/devtools/pull/4700) - - ![coverage](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4700.png "coverage in CodeView") - -## Network updates - -* Display request data if content type is not json - (thanks to @leungpuikuen!) - - [#4602](https://github.com/flutter/devtools/pull/4602) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.19.0...v2.20.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.20.0.md b/src/content/tools/devtools/release-notes/release-notes-2.20.0.md index a5af343dc43..3a146eabca0 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.20.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.20.0.md @@ -1,7 +1,68 @@ --- +title: DevTools 2.20.0 release notes shortTitle: 2.20.0 release notes +breadcrumb: 2.20.0 description: Release notes for Dart and Flutter DevTools version 2.20.0. showToc: false --- -{% include ./release-notes-2.20.0-src.md %} +The 2.20.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## CPU profiler updates + +* Add support for grouping samples by tag - + [#4693](https://github.com/flutter/devtools/pull/4693) + + ![samples by tag](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4693.png "samples by tag") + +* Enable guidelines for tree view - + [#4722](https://github.com/flutter/devtools/pull/4722) + + ![guidelines](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4722.png "guidelines") + +* Rename "Profile granularity" to "CPU sampling rate" + and move down to the area it relates to - + [#4803](https://github.com/flutter/devtools/pull/4722) + + ![sampling rate](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4803.png "sampling rate") + + +## Memory updates + +* Retire the **Analysis** tab - + [#4714](https://github.com/flutter/devtools/pull/4714) + +* Add a new tab, **Diff**, to enable memory leak detection + and troubleshooting by comparing heap snapshots, + providing insights about the number of instances, + shallow size, retained size, and retaining paths - + [#4714](https://github.com/flutter/devtools/pull/4714) + + ![diff](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4714.png "Diff in Memory tab") + +## Debugger updates + +* Support for inspecting more types of instances in the variables viewer + (Expandos, Types, TypeArguments, Parameters, Closures + closure Contexts, + WeakProperty, Function, FunctionType, ReceivePort, Closure, RegExp) - + [#4760](https://github.com/flutter/devtools/pull/4760) + +* Add support for displaying coverage in CodeView - + [#4700](https://github.com/flutter/devtools/pull/4700) + + ![coverage](/assets/images/docs/tools/devtools/release-notes/images-2.20.0/4700.png "coverage in CodeView") + +## Network updates + +* Display request data if content type is not json + (thanks to @leungpuikuen!) - + [#4602](https://github.com/flutter/devtools/pull/4602) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.19.0...v2.20.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.21.1-src.md b/src/content/tools/devtools/release-notes/release-notes-2.21.1-src.md deleted file mode 100644 index 249d41aec3d..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.21.1-src.md +++ /dev/null @@ -1,69 +0,0 @@ -# DevTools 2.21.1 release notes - -The 2.21.1 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## Performance updates - -* Replace the DevTools timeline trace viewer with - the [Perfetto](https://perfetto.dev/) trace viewer - - [#5142](https://github.com/flutter/devtools/pull/5142) - - ![perfetto trace viewer](/assets/images/docs/tools/devtools/release-notes/images-2.21.1/image1.png "perfetto_trace_viewer") - -* Fix several issues with loading a Performance snapshot into DevTools - - [#5048](https://github.com/flutter/devtools/pull/5048), - [#4929](https://github.com/flutter/devtools/pull/4929) -* UI polish and cleanup - [#4889](https://github.com/flutter/devtools/pull/4889) - -## Memory updates - -* Improve usability of snapshot diffing - - [#5015](https://github.com/flutter/devtools/pull/5015) -* UI polish and cleanup - - [#4855](https://github.com/flutter/devtools/pull/4855) -* Color code classes based on where they are defined - (SDK, your package, dependencies, etc.) - - [#5030](https://github.com/flutter/devtools/pull/5030) -* Fix state management issue for tracing - - [#5062](https://github.com/flutter/devtools/pull/5062) -* Improve the performance of taking a heap snapshot - - [#5134](https://github.com/flutter/devtools/pull/5134) -* Retire broken import/export feature - - [#5135](https://github.com/flutter/devtools/pull/5135) - -## Debugger updates - -* Added support for viewing profiler hits in - the debugger script viewer - - [#4831](https://github.com/flutter/devtools/pull/4831) -* Added support for inspecting records - - [#5084](https://github.com/flutter/devtools/pull/5084) - -## General updates - -* Fix several issues in syntax highlighting that would - color variable names that contain reserved words incorrectly and - leave `extends`/`implements` clauses uncolored for some classes - - [#4948](https://github.com/flutter/devtools/pull/4948) -* Fix an issue in Safari, and - other browsers that do not support RegExp negative lookbehind, - that prevented DevTools from loading - - [#4938](https://github.com/flutter/devtools/pull/4938) -* Fix an issue that would prevent DevTools connecting to - the backend server that would disable some functionality - - [#5016](https://github.com/flutter/devtools/pull/5016) -* Add a link to the DevTools - [contribution guide](https://github.com/flutter/devtools/blob/master/CONTRIBUTING.md) - to the About menu, and fixed the Discord link - - [#4926](https://github.com/flutter/devtools/pull/4926) -* Fix conflicting colors in light theme - - [#5067](https://github.com/flutter/devtools/pull/5067) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.20.0...v2.21.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.21.1.md b/src/content/tools/devtools/release-notes/release-notes-2.21.1.md index 80ed185e3c3..d8cd8828ccf 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.21.1.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.21.1.md @@ -1,7 +1,75 @@ --- +title: DevTools 2.21.1 release notes shortTitle: 2.21.1 release notes +breadcrumb: 2.22.1 description: Release notes for Dart and Flutter DevTools version 2.21.1. showToc: false --- -{% include ./release-notes-2.21.1-src.md %} +The 2.21.1 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## Performance updates + +* Replace the DevTools timeline trace viewer with + the [Perfetto](https://perfetto.dev/) trace viewer - + [#5142](https://github.com/flutter/devtools/pull/5142) + + ![perfetto trace viewer](/assets/images/docs/tools/devtools/release-notes/images-2.21.1/image1.png "perfetto_trace_viewer") + +* Fix several issues with loading a Performance snapshot into DevTools - + [#5048](https://github.com/flutter/devtools/pull/5048), + [#4929](https://github.com/flutter/devtools/pull/4929) +* UI polish and cleanup - [#4889](https://github.com/flutter/devtools/pull/4889) + +## Memory updates + +* Improve usability of snapshot diffing - + [#5015](https://github.com/flutter/devtools/pull/5015) +* UI polish and cleanup - + [#4855](https://github.com/flutter/devtools/pull/4855) +* Color code classes based on where they are defined + (SDK, your package, dependencies, etc.) - + [#5030](https://github.com/flutter/devtools/pull/5030) +* Fix state management issue for tracing - + [#5062](https://github.com/flutter/devtools/pull/5062) +* Improve the performance of taking a heap snapshot - + [#5134](https://github.com/flutter/devtools/pull/5134) +* Retire broken import/export feature - + [#5135](https://github.com/flutter/devtools/pull/5135) + +## Debugger updates + +* Added support for viewing profiler hits in + the debugger script viewer - + [#4831](https://github.com/flutter/devtools/pull/4831) +* Added support for inspecting records - + [#5084](https://github.com/flutter/devtools/pull/5084) + +## General updates + +* Fix several issues in syntax highlighting that would + color variable names that contain reserved words incorrectly and + leave `extends`/`implements` clauses uncolored for some classes - + [#4948](https://github.com/flutter/devtools/pull/4948) +* Fix an issue in Safari, and + other browsers that do not support RegExp negative lookbehind, + that prevented DevTools from loading - + [#4938](https://github.com/flutter/devtools/pull/4938) +* Fix an issue that would prevent DevTools connecting to + the backend server that would disable some functionality - + [#5016](https://github.com/flutter/devtools/pull/5016) +* Add a link to the DevTools + [contribution guide](https://github.com/flutter/devtools/blob/master/CONTRIBUTING.md) + to the About menu, and fixed the Discord link - + [#4926](https://github.com/flutter/devtools/pull/4926) +* Fix conflicting colors in light theme - + [#5067](https://github.com/flutter/devtools/pull/5067) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.20.0...v2.21.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.22.2-src.md b/src/content/tools/devtools/release-notes/release-notes-2.22.2-src.md deleted file mode 100644 index 85f26f7829a..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.22.2-src.md +++ /dev/null @@ -1,69 +0,0 @@ -# DevTools 2.22.2 release notes - -The 2.22.2 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -- Prevent crashes if there is no main isolate - - [#5232](https://github.com/flutter/devtools/pull/5232) - -## CPU profiler updates - -- Display stack frame URI inline with method name to - ensure the URI is always visible in deeply nested trees - - [#5181](https://github.com/flutter/devtools/pull/5181) - - ![inline uri](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5181.png "inline uri") - -- Add the ability to filter by method name or source URI - - [#5204](https://github.com/flutter/devtools/pull/5204) - -## Memory updates - -- Change filter default to show only project and 3rd party dependencies - - [#5201](https://github.com/flutter/devtools/pull/5201). - - ![filter default](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5201.png "filter default") - -- Support expression evaluation in console for running application - - [#5248](https://github.com/flutter/devtools/pull/5248). - - ![evaluation](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5248.png "evaluation") - -- Add column `Persisted` for memory diffing - - [#5290](https://github.com/flutter/devtools/pull/5290) - - ![persisted](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5290.png "persisted") - -## Debugger updates - -- Add support for browser navigation history when - navigating using the File Explorer - - [#4906](https://github.com/flutter/devtools/pull/4906) -- Designate positional fields for `Record` types - with the getter syntax beginning at `$1` - - [#5272](https://github.com/flutter/devtools/pull/5272) -- Fix variable inspection for `Map` and `List` instances - - [#5320](https://github.com/flutter/devtools/pull/5320) - - ![map and list](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5320.png "map and list") - -- Fix variable inspection for `Set` instances - - [#5323](https://github.com/flutter/devtools/pull/5323) - - ![set](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5323.png "set") - - -## Network profiler updates - -- Improve reliability and performance of the Network tab - - [#5056](https://github.com/flutter/devtools/pull/5056) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.21.1...v2.22.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.22.2.md b/src/content/tools/devtools/release-notes/release-notes-2.22.2.md index aad3de8327c..e0fc4dba327 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.22.2.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.22.2.md @@ -1,7 +1,75 @@ --- +title: DevTools 2.22.2 release notes shortTitle: 2.22.2 release notes +breadcrumb: 2.22.2 description: Release notes for Dart and Flutter DevTools version 2.22.2. showToc: false --- -{% include ./release-notes-2.22.2-src.md %} +The 2.22.2 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +- Prevent crashes if there is no main isolate - + [#5232](https://github.com/flutter/devtools/pull/5232) + +## CPU profiler updates + +- Display stack frame URI inline with method name to + ensure the URI is always visible in deeply nested trees - + [#5181](https://github.com/flutter/devtools/pull/5181) + + ![inline uri](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5181.png "inline uri") + +- Add the ability to filter by method name or source URI - + [#5204](https://github.com/flutter/devtools/pull/5204) + +## Memory updates + +- Change filter default to show only project and 3rd party dependencies - + [#5201](https://github.com/flutter/devtools/pull/5201). + + ![filter default](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5201.png "filter default") + +- Support expression evaluation in console for running application - + [#5248](https://github.com/flutter/devtools/pull/5248). + + ![evaluation](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5248.png "evaluation") + +- Add column `Persisted` for memory diffing - + [#5290](https://github.com/flutter/devtools/pull/5290) + + ![persisted](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5290.png "persisted") + +## Debugger updates + +- Add support for browser navigation history when + navigating using the File Explorer - + [#4906](https://github.com/flutter/devtools/pull/4906) +- Designate positional fields for `Record` types + with the getter syntax beginning at `$1` - + [#5272](https://github.com/flutter/devtools/pull/5272) +- Fix variable inspection for `Map` and `List` instances - + [#5320](https://github.com/flutter/devtools/pull/5320) + + ![map and list](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5320.png "map and list") + +- Fix variable inspection for `Set` instances - + [#5323](https://github.com/flutter/devtools/pull/5323) + + ![set](/assets/images/docs/tools/devtools/release-notes/images-2.22.2/5323.png "set") + + +## Network profiler updates + +- Improve reliability and performance of the Network tab - + [#5056](https://github.com/flutter/devtools/pull/5056) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.21.1...v2.22.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.23.1-src.md b/src/content/tools/devtools/release-notes/release-notes-2.23.1-src.md deleted file mode 100644 index 80489f2c184..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.23.1-src.md +++ /dev/null @@ -1,112 +0,0 @@ -# DevTools 2.23.1 release notes - -The 2.23.1 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Update DevTools to the new Material 3 design - - [#5429](https://github.com/flutter/devtools/pull/5429) -* Use the default Flutter service worker - - [#5331](https://github.com/flutter/devtools/pull/5331) -* Added the new verbose logging feature for helping us debug user issues - - [#5404](https://github.com/flutter/devtools/pull/5404) - - ![verbose logging](/assets/images/docs/tools/devtools/release-notes/images-2.23.1/verbose-logging.png "verbose_logging") - -* Fix a bug where some asynchronous errors were not being reported - - [#5456](https://github.com/flutter/devtools/pull/5456) -* Added support for viewing data after an app disconnects for - screens that support offline viewing - (currently only the Performance and CPU profiler pages) - - [#5509](https://github.com/flutter/devtools/pull/5509) -* Include settings button in the footer of the embedded view - - [#5528](https://github.com/flutter/devtools/pull/5528) - -## Performance updates - -* Fix a performance regression in timeline event processing - - [#5460](https://github.com/flutter/devtools/pull/5460) -* Persist a user's preference for whether the - Flutter Frames chart should be shown by default - - [#5339](https://github.com/flutter/devtools/pull/5339) -* Point users to [Impeller](https://docs.flutter.dev/perf/impeller) when - shader compilation jank is detected on an iOS device - - [#5455](https://github.com/flutter/devtools/pull/5455) -* Remove the CPU profiler from the legacy trace viewer - - [#5539](https://github.com/flutter/devtools/pull/5539) - -## CPU profiler updates - -* Add a Method Table to the CPU profiler - - [#5366](https://github.com/flutter/devtools/pull/5366) - - ![Method table](/assets/images/docs/tools/devtools/release-notes/images-2.23.1/cpu-method-table.png "method_table") - -* Improve the performance of data processing in the CPU profiler - - [#5468](https://github.com/flutter/devtools/pull/5468), - [#5533](https://github.com/flutter/devtools/pull/5533), - [#5535](https://github.com/flutter/devtools/pull/5535) -* Polish and performance improvements for the CPU profile flame chart - - [#5529](https://github.com/flutter/devtools/pull/5529) -* Add ability to inspect statistics for a CPU profile - - [#5340](https://github.com/flutter/devtools/pull/5340) -* Fix a bug where Native stack frames were missing their name - - [#5344](https://github.com/flutter/devtools/pull/5344) -* Fix an error in total and self time calculations for the bottom up tree - - [#5348](https://github.com/flutter/devtools/pull/5348) -* Add support for zooming and navigating the flame chart - with ,AOE keys (helpful for Dvorak users) - - [#5545](https://github.com/flutter/devtools/pull/5545) - -## Memory updates - -* Fix filtering bug in the "Trace Instances" view - - [#5406](https://github.com/flutter/devtools/pull/5406) -* Enabled evaluation and browsing for instances in heap snapshot - - [#5542](https://github.com/flutter/devtools/pull/5542) -* Fix heap snapshot failure - - [#5520](https://github.com/flutter/devtools/pull/5520) -* Stop displaying external sizes in the allocation profile - - [#5555](https://github.com/flutter/devtools/pull/5555) -* Expose totals for memory in heap snapshot - - [#5593](https://github.com/flutter/devtools/pull/5593) - -## Debugger updates - -* Fix a bug where variable inspection - for instances sometimes showed no children - - [#5356](https://github.com/flutter/devtools/pull/5356) -* Hide "search in file" dialog if the "file search" dialog is open - - [#5393](https://github.com/flutter/devtools/pull/5393) -* Fix file search bug where last letter disappeared when - searching at end of file name - - [#5397](https://github.com/flutter/devtools/pull/5397) -* Add search icon in file bar to make file search more discoverable - - [#5351](https://github.com/flutter/devtools/issues/5351) -* Allow expression evaluation when pausing in JS for web apps - - [#5427](https://github.com/flutter/devtools/pull/5427) -* Update syntax highlighting to - [dart-lang/dart-syntax-highlight v1.2.0](https://github.com/dart-lang/dart-syntax-highlight/blob/master/CHANGELOG.md#120-2023-01-30) - - [#5477](https://github.com/flutter/devtools/pull/5477) -* Debugger panel respects "dense mode" - - [#5517](https://github.com/flutter/devtools/pull/5517) - -## Network profiler updates - -* Fix a bug viewing JSON responses with null values - - [#5424](https://github.com/flutter/devtools/pull/5424) -* Fix a bug where JSON requests were shown in plain text, - instead of the formatted JSON viewer - - [#5463](https://github.com/flutter/devtools/pull/5463) -* Fix a UI issue where the copy button on the response or request tab - would let you copy while still loading the data - - [#5476](https://github.com/flutter/devtools/pull/5476) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.22.2...v2.23.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.23.1.md b/src/content/tools/devtools/release-notes/release-notes-2.23.1.md index eba25a5a64c..76ca5c772b1 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.23.1.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.23.1.md @@ -1,7 +1,118 @@ --- +title: DevTools 2.23.1 release notes shortTitle: 2.23.1 release notes +breadcrumb: 2.23.1 description: Release notes for Dart and Flutter DevTools version 2.23.1. showToc: false --- -{% include ./release-notes-2.23.1-src.md %} +The 2.23.1 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Update DevTools to the new Material 3 design - + [#5429](https://github.com/flutter/devtools/pull/5429) +* Use the default Flutter service worker - + [#5331](https://github.com/flutter/devtools/pull/5331) +* Added the new verbose logging feature for helping us debug user issues - + [#5404](https://github.com/flutter/devtools/pull/5404) + + ![verbose logging](/assets/images/docs/tools/devtools/release-notes/images-2.23.1/verbose-logging.png "verbose_logging") + +* Fix a bug where some asynchronous errors were not being reported - + [#5456](https://github.com/flutter/devtools/pull/5456) +* Added support for viewing data after an app disconnects for + screens that support offline viewing + (currently only the Performance and CPU profiler pages) - + [#5509](https://github.com/flutter/devtools/pull/5509) +* Include settings button in the footer of the embedded view - + [#5528](https://github.com/flutter/devtools/pull/5528) + +## Performance updates + +* Fix a performance regression in timeline event processing - + [#5460](https://github.com/flutter/devtools/pull/5460) +* Persist a user's preference for whether the + Flutter Frames chart should be shown by default - + [#5339](https://github.com/flutter/devtools/pull/5339) +* Point users to [Impeller](https://docs.flutter.dev/perf/impeller) when + shader compilation jank is detected on an iOS device - + [#5455](https://github.com/flutter/devtools/pull/5455) +* Remove the CPU profiler from the legacy trace viewer - + [#5539](https://github.com/flutter/devtools/pull/5539) + +## CPU profiler updates + +* Add a Method Table to the CPU profiler - + [#5366](https://github.com/flutter/devtools/pull/5366) + + ![Method table](/assets/images/docs/tools/devtools/release-notes/images-2.23.1/cpu-method-table.png "method_table") + +* Improve the performance of data processing in the CPU profiler - + [#5468](https://github.com/flutter/devtools/pull/5468), + [#5533](https://github.com/flutter/devtools/pull/5533), + [#5535](https://github.com/flutter/devtools/pull/5535) +* Polish and performance improvements for the CPU profile flame chart - + [#5529](https://github.com/flutter/devtools/pull/5529) +* Add ability to inspect statistics for a CPU profile - + [#5340](https://github.com/flutter/devtools/pull/5340) +* Fix a bug where Native stack frames were missing their name - + [#5344](https://github.com/flutter/devtools/pull/5344) +* Fix an error in total and self time calculations for the bottom up tree - + [#5348](https://github.com/flutter/devtools/pull/5348) +* Add support for zooming and navigating the flame chart + with ,AOE keys (helpful for Dvorak users) - + [#5545](https://github.com/flutter/devtools/pull/5545) + +## Memory updates + +* Fix filtering bug in the "Trace Instances" view - + [#5406](https://github.com/flutter/devtools/pull/5406) +* Enabled evaluation and browsing for instances in heap snapshot - + [#5542](https://github.com/flutter/devtools/pull/5542) +* Fix heap snapshot failure - + [#5520](https://github.com/flutter/devtools/pull/5520) +* Stop displaying external sizes in the allocation profile - + [#5555](https://github.com/flutter/devtools/pull/5555) +* Expose totals for memory in heap snapshot - + [#5593](https://github.com/flutter/devtools/pull/5593) + +## Debugger updates + +* Fix a bug where variable inspection + for instances sometimes showed no children - + [#5356](https://github.com/flutter/devtools/pull/5356) +* Hide "search in file" dialog if the "file search" dialog is open - + [#5393](https://github.com/flutter/devtools/pull/5393) +* Fix file search bug where last letter disappeared when + searching at end of file name - + [#5397](https://github.com/flutter/devtools/pull/5397) +* Add search icon in file bar to make file search more discoverable - + [#5351](https://github.com/flutter/devtools/issues/5351) +* Allow expression evaluation when pausing in JS for web apps - + [#5427](https://github.com/flutter/devtools/pull/5427) +* Update syntax highlighting to + [dart-lang/dart-syntax-highlight v1.2.0](https://github.com/dart-lang/dart-syntax-highlight/blob/master/CHANGELOG.md#120-2023-01-30) - + [#5477](https://github.com/flutter/devtools/pull/5477) +* Debugger panel respects "dense mode" - + [#5517](https://github.com/flutter/devtools/pull/5517) + +## Network profiler updates + +* Fix a bug viewing JSON responses with null values - + [#5424](https://github.com/flutter/devtools/pull/5424) +* Fix a bug where JSON requests were shown in plain text, + instead of the formatted JSON viewer - + [#5463](https://github.com/flutter/devtools/pull/5463) +* Fix a UI issue where the copy button on the response or request tab + would let you copy while still loading the data - + [#5476](https://github.com/flutter/devtools/pull/5476) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.22.2...v2.23.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.24.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.24.0-src.md deleted file mode 100644 index bb5114b24a5..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.24.0-src.md +++ /dev/null @@ -1,45 +0,0 @@ -# DevTools 2.24.0 release notes - -The 2.24.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Improve the overall performance of DevTools tables - - [#5664](https://github.com/flutter/devtools/pull/5664), - [#5696](https://github.com/flutter/devtools/pull/5696) - -## CPU profiler updates - -* Fix bug with CPU flame chart selection and tooltips - - [#5676](https://github.com/flutter/devtools/pull/5676) - -## Debugger updates - -* Improve support for inspecting - `UserTag` and `MirrorReferent` instances - - [#5490](https://github.com/flutter/devtools/pull/5490) -* Fix expression evaluation bug where - selecting an autocomplete result for a field would clear the current input - - [#5717](https://github.com/flutter/devtools/pull/5717) -* Make selection of a stack frame - scroll to the frame location in the source code - - [#5722](https://github.com/flutter/devtools/pull/5722) -* Improve performance of searching for a file and searching in a file - - [#5733](https://github.com/flutter/devtools/pull/5733) -* Disable syntax highlighting for files with more than 100,000 characters - due to performance constraints - - [#5743](https://github.com/flutter/devtools/pull/5743) -* Fix bug where source code wasn't visible if - syntax highlighting for a file was disabled - - [#5743](https://github.com/flutter/devtools/pull/5743) -* Prevent file names and source code from getting out of sync - - [#5827](https://github.com/flutter/devtools/pull/5827) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.23.1...v2.24.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.24.0.md b/src/content/tools/devtools/release-notes/release-notes-2.24.0.md index 7f3b9994ef3..bf9982c2adb 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.24.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.24.0.md @@ -1,7 +1,51 @@ --- +title: DevTools 2.24.0 release notes shortTitle: 2.24.0 release notes +breadcrumb: 2.24.0 description: Release notes for Dart and Flutter DevTools version 2.24.0. showToc: false --- -{% include ./release-notes-2.24.0-src.md %} +The 2.24.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Improve the overall performance of DevTools tables - + [#5664](https://github.com/flutter/devtools/pull/5664), + [#5696](https://github.com/flutter/devtools/pull/5696) + +## CPU profiler updates + +* Fix bug with CPU flame chart selection and tooltips - + [#5676](https://github.com/flutter/devtools/pull/5676) + +## Debugger updates + +* Improve support for inspecting + `UserTag` and `MirrorReferent` instances - + [#5490](https://github.com/flutter/devtools/pull/5490) +* Fix expression evaluation bug where + selecting an autocomplete result for a field would clear the current input - + [#5717](https://github.com/flutter/devtools/pull/5717) +* Make selection of a stack frame + scroll to the frame location in the source code - + [#5722](https://github.com/flutter/devtools/pull/5722) +* Improve performance of searching for a file and searching in a file - + [#5733](https://github.com/flutter/devtools/pull/5733) +* Disable syntax highlighting for files with more than 100,000 characters + due to performance constraints - + [#5743](https://github.com/flutter/devtools/pull/5743) +* Fix bug where source code wasn't visible if + syntax highlighting for a file was disabled - + [#5743](https://github.com/flutter/devtools/pull/5743) +* Prevent file names and source code from getting out of sync - + [#5827](https://github.com/flutter/devtools/pull/5827) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.23.1...v2.24.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.25.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.25.0-src.md deleted file mode 100644 index fc4005a6b45..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.25.0-src.md +++ /dev/null @@ -1,28 +0,0 @@ -# DevTools 2.25.0 release notes - -The 2.25.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -- Improve DevTools tab bar navigation when the list of tabs is long - - [#5875](https://github.com/flutter/devtools/pull/5875) -- Clear registered service methods between app connections - - [#5960](https://github.com/flutter/devtools/pull/5960) - -## Memory updates - -- Add legend for class types - - [#5937](https://github.com/flutter/devtools/pull/5937) -- Enable sampling for Memory > Profile - - [#5947](https://github.com/flutter/devtools/pull/5947) - - ![memory sampling](/assets/images/docs/tools/devtools/release-notes/images-2.25.0/memory.png "memory_sampling") - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.24.0...v2.25.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.25.0.md b/src/content/tools/devtools/release-notes/release-notes-2.25.0.md index 78a835ede25..c168ddff487 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.25.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.25.0.md @@ -1,7 +1,34 @@ --- +title: DevTools 2.25.0 release notes shortTitle: 2.25.0 release notes +breadcrumb: 2.25.0 description: Release notes for Dart and Flutter DevTools version 2.25.0. showToc: false --- -{% include ./release-notes-2.25.0-src.md %} +The 2.25.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +- Improve DevTools tab bar navigation when the list of tabs is long - + [#5875](https://github.com/flutter/devtools/pull/5875) +- Clear registered service methods between app connections - + [#5960](https://github.com/flutter/devtools/pull/5960) + +## Memory updates + +- Add legend for class types - + [#5937](https://github.com/flutter/devtools/pull/5937) +- Enable sampling for Memory > Profile - + [#5947](https://github.com/flutter/devtools/pull/5947) + + ![memory sampling](/assets/images/docs/tools/devtools/release-notes/images-2.25.0/memory.png "memory_sampling") + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.24.0...v2.25.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.26.1-src.md b/src/content/tools/devtools/release-notes/release-notes-2.26.1-src.md deleted file mode 100644 index d072a489aa2..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.26.1-src.md +++ /dev/null @@ -1,47 +0,0 @@ -# DevTools 2.26.1 release notes - -The 2.26.1 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -- Added a new "Home" screen in DevTools that either shows the "Connect" dialog - or a summary of your connected app, depending on - the connection status in DevTools. - Keep an eye on this screen for cool new features in the future. - This change also enables support for static tooling - (tools that don't require a connected app) in DevTools - - [#6010](https://github.com/flutter/devtools/pull/6010) - - ![home screen](/assets/images/docs/tools/devtools/release-notes/images-2.26.1/home_screen.png "DevTools home screen") - -- Fixed overlay notifications so that they - cover the area that their background blocks - - [#5975](https://github.com/flutter/devtools/pull/5975) - -## Memory updates - -- Added a context menu to rename or delete a heap snapshot from the list - - [#5997](https://github.com/flutter/devtools/pull/5997) -- Warn users when HTTP logging may be affecting their app's memory consumption - - [#5998](https://github.com/flutter/devtools/pull/5998) - -## Debugger updates - -- Improvements to text selection and copy behavior in - the code view, console, and variables windows - - [#6020](https://github.com/flutter/devtools/pull/6020) - -## Network profiler updates - -- Added a selector to customize the display type - of text and json responses (thanks to @hhacker1999!) - - [#5816](https://github.com/flutter/devtools/pull/5816) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.25.0...v2.26.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.26.1.md b/src/content/tools/devtools/release-notes/release-notes-2.26.1.md index 9ddbf56a148..60fd6604d0a 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.26.1.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.26.1.md @@ -1,7 +1,53 @@ --- +title: DevTools 2.26.1 release notes shortTitle: 2.26.1 release notes +breadcrumb: 2.26.1 description: Release notes for Dart and Flutter DevTools version 2.26.1. showToc: false --- -{% include ./release-notes-2.26.1-src.md %} +The 2.26.1 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +- Added a new "Home" screen in DevTools that either shows the "Connect" dialog + or a summary of your connected app, depending on + the connection status in DevTools. + Keep an eye on this screen for cool new features in the future. + This change also enables support for static tooling + (tools that don't require a connected app) in DevTools - + [#6010](https://github.com/flutter/devtools/pull/6010) + + ![home screen](/assets/images/docs/tools/devtools/release-notes/images-2.26.1/home_screen.png "DevTools home screen") + +- Fixed overlay notifications so that they + cover the area that their background blocks - + [#5975](https://github.com/flutter/devtools/pull/5975) + +## Memory updates + +- Added a context menu to rename or delete a heap snapshot from the list - + [#5997](https://github.com/flutter/devtools/pull/5997) +- Warn users when HTTP logging may be affecting their app's memory consumption - + [#5998](https://github.com/flutter/devtools/pull/5998) + +## Debugger updates + +- Improvements to text selection and copy behavior in + the code view, console, and variables windows - + [#6020](https://github.com/flutter/devtools/pull/6020) + +## Network profiler updates + +- Added a selector to customize the display type + of text and json responses (thanks to @hhacker1999!) - + [#5816](https://github.com/flutter/devtools/pull/5816) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.25.0...v2.26.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.27.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.27.0-src.md deleted file mode 100644 index 0597401fdf6..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.27.0-src.md +++ /dev/null @@ -1,19 +0,0 @@ -# DevTools 2.27.0 release notes - -The 2.27.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## Network profiler updates - -- Fix a crash with large text in network requests and responses - - [#6254](https://github.com/flutter/devtools/pull/6254) - - ![Example truncation of text in the network view](/assets/images/docs/tools/devtools/release-notes/images-2.27.0/truncation.png "Example truncation of text in the network view") - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.26.1...v2.27.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.27.0.md b/src/content/tools/devtools/release-notes/release-notes-2.27.0.md index 73d4a0483ff..01133555e7a 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.27.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.27.0.md @@ -1,7 +1,25 @@ --- +title: DevTools 2.27.0 release notes shortTitle: 2.27.0 release notes +breadcrumb: 2.27.0 description: Release notes for Dart and Flutter DevTools version 2.27.0. showToc: false --- -{% include ./release-notes-2.27.0-src.md %} +The 2.27.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## Network profiler updates + +- Fix a crash with large text in network requests and responses - + [#6254](https://github.com/flutter/devtools/pull/6254) + + ![Example truncation of text in the network view](/assets/images/docs/tools/devtools/release-notes/images-2.27.0/truncation.png "Example truncation of text in the network view") + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.26.1...v2.27.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.1-src.md b/src/content/tools/devtools/release-notes/release-notes-2.28.1-src.md deleted file mode 100644 index cfb40f87568..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.1-src.md +++ /dev/null @@ -1,50 +0,0 @@ -# DevTools 2.28.1 release notes - -The 2.28.1 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Added support for DevTools extensions. - This means if you are debugging an app that depends on `package:foo`, - and `package:foo` provides a DevTools extension, - you will see a "Foo" tab display in DevTools - that you can use to debug your app. - To provide a DevTools extension for your pub package, - check out the getting started guide for - [package:devtools_extensions](https://pub.dev/packages/devtools_extensions)! - -![Example DevTools extension](/assets/images/docs/tools/devtools/release-notes/images-2.28.1/example_devtools_extension.png "Example DevTools extension for package:foo_package") - -* Fixed theming bug in isolate selector - - [#6403](https://github.com/flutter/devtools/pull/6403) -* Fixed isolate bug where main isolate was not reselecting on hot restart - - [#6436](https://github.com/flutter/devtools/pull/6436) -* Show the hot reload button for Dart server apps that support hot reload - - [#6341](https://github.com/flutter/devtools/pull/6341) -* Fixed exceptions on hot restart - - [#6451](https://github.com/flutter/devtools/pull/6451), - [#6450](https://github.com/flutter/devtools/pull/6450) - -## Inspector updates - -* Fixed bug where inspector service calls were done on the selected isolate, - instead of the main isolate - - [#6434](https://github.com/flutter/devtools/pull/6434) - -## Logging updates - -* Improved responsiveness of the top bar on the Logging view - - [#6281](https://github.com/flutter/devtools/pull/6281) - -* Added the ability to copy filtered logs - - [#6260](https://github.com/flutter/devtools/pull/6260) - - ![The copy button on the Logging view to the right of the filter tool](/assets/images/docs/tools/devtools/release-notes/images-2.28.1/logger_copy.png "The Logging view copy button") - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.1.md b/src/content/tools/devtools/release-notes/release-notes-2.28.1.md index 2786f5542b8..7f1157755af 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.1.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.28.1.md @@ -1,7 +1,56 @@ --- +title: DevTools 2.28.1 release notes shortTitle: 2.28.1 release notes +breadcrumb: 2.28.1 description: Release notes for Dart and Flutter DevTools version 2.28.1. showToc: false --- -{% include ./release-notes-2.28.1-src.md %} +The 2.28.1 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Added support for DevTools extensions. + This means if you are debugging an app that depends on `package:foo`, + and `package:foo` provides a DevTools extension, + you will see a "Foo" tab display in DevTools + that you can use to debug your app. + To provide a DevTools extension for your pub package, + check out the getting started guide for + [package:devtools_extensions](https://pub.dev/packages/devtools_extensions)! + +![Example DevTools extension](/assets/images/docs/tools/devtools/release-notes/images-2.28.1/example_devtools_extension.png "Example DevTools extension for package:foo_package") + +* Fixed theming bug in isolate selector - + [#6403](https://github.com/flutter/devtools/pull/6403) +* Fixed isolate bug where main isolate was not reselecting on hot restart - + [#6436](https://github.com/flutter/devtools/pull/6436) +* Show the hot reload button for Dart server apps that support hot reload - + [#6341](https://github.com/flutter/devtools/pull/6341) +* Fixed exceptions on hot restart - + [#6451](https://github.com/flutter/devtools/pull/6451), + [#6450](https://github.com/flutter/devtools/pull/6450) + +## Inspector updates + +* Fixed bug where inspector service calls were done on the selected isolate, + instead of the main isolate - + [#6434](https://github.com/flutter/devtools/pull/6434) + +## Logging updates + +* Improved responsiveness of the top bar on the Logging view - + [#6281](https://github.com/flutter/devtools/pull/6281) + +* Added the ability to copy filtered logs - + [#6260](https://github.com/flutter/devtools/pull/6260) + + ![The copy button on the Logging view to the right of the filter tool](/assets/images/docs/tools/devtools/release-notes/images-2.28.1/logger_copy.png "The Logging view copy button") + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.2-src.md b/src/content/tools/devtools/release-notes/release-notes-2.28.2-src.md deleted file mode 100644 index 6641d934117..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.2-src.md +++ /dev/null @@ -1,22 +0,0 @@ -# DevTools 2.28.2 release notes - -The 2.28.2 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -This was a cherry-pick release on top of DevTools 2.28.1. -To learn about the improvements included in DevTools 2.28.1, please read the -[release notes](/tools/devtools/release-notes/release-notes-2.28.1). - -## DevTools Extension updates - -* Enabled DevTools extensions when debugging a Dart entry point that is not - under `lib` (e.g. a unit test or integration test). Thanks to - [@bartekpacia](https://github.com/bartekpacia) for this change! - - [#6644](https://github.com/flutter/devtools/pull/6644) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.2.md b/src/content/tools/devtools/release-notes/release-notes-2.28.2.md index d756130f76d..f407fe7db5e 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.2.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.28.2.md @@ -1,7 +1,28 @@ --- +title: DevTools 2.28.2 release notes shortTitle: 2.28.2 release notes +breadcrumb: 2.28.2 description: Release notes for Dart and Flutter DevTools version 2.28.2. showToc: false --- -{% include ./release-notes-2.28.2-src.md %} +The 2.28.2 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +This was a cherry-pick release on top of DevTools 2.28.1. +To learn about the improvements included in DevTools 2.28.1, please read the +[release notes](/tools/devtools/release-notes/release-notes-2.28.1). + +## DevTools Extension updates + +* Enabled DevTools extensions when debugging a Dart entry point that is not + under `lib` (e.g. a unit test or integration test). Thanks to + [@bartekpacia](https://github.com/bartekpacia) for this change! - + [#6644](https://github.com/flutter/devtools/pull/6644) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.3-src.md b/src/content/tools/devtools/release-notes/release-notes-2.28.3-src.md deleted file mode 100644 index c652b16ce43..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.3-src.md +++ /dev/null @@ -1,36 +0,0 @@ -# DevTools 2.28.3 release notes - -The 2.28.3 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -This was a cherry-pick release on top of DevTools 2.28.2. -To learn about the improvements included in DevTools 2.28.2, please read the -[release notes](/tools/devtools/release-notes/release-notes-2.28.2). - -## General updates - -* Added a link to the new "Dive in to DevTools" YouTube - [video](https://www.youtube.com/watch?v=_EYk-E29edo) in the bottom status bar. - This video provides a brief tutorial for each DevTools screen. - [#6554](https://github.com/flutter/devtools/pull/6554) - - ![Link to watch a DevTools tutorial video](/assets/images/docs/tools/devtools/release-notes/images-2.28.3/watch_tutorial_link.png "Link to watch a DevTools tutorial video") - -* Added a workaround to fix copy button functionality in VSCode. - [#6598](https://github.com/flutter/devtools/pull/6598) - -## Performance updates - -* Disable the Raster Stats tool for the Impeller backend - since it is not supported. - [#6616](https://github.com/flutter/devtools/pull/6616) - -## VS Code Sidebar updates - -* When using VS Code with a light theme, the embedded sidebar provided by - DevTools will now also show in the light theme. - [#6581](https://github.com/flutter/devtools/pull/6581) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.3). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.3.md b/src/content/tools/devtools/release-notes/release-notes-2.28.3.md index c0464521477..6ebbbad0cd6 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.3.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.28.3.md @@ -1,7 +1,42 @@ --- +title: DevTools 2.28.3 release notes shortTitle: 2.28.3 release notes +breadcrumb: 2.28.3 description: Release notes for Dart and Flutter DevTools version 2.28.3. showToc: false --- -{% include ./release-notes-2.28.3-src.md %} +The 2.28.3 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +This was a cherry-pick release on top of DevTools 2.28.2. +To learn about the improvements included in DevTools 2.28.2, please read the +[release notes](/tools/devtools/release-notes/release-notes-2.28.2). + +## General updates + +* Added a link to the new "Dive in to DevTools" YouTube + [video](https://www.youtube.com/watch?v=_EYk-E29edo) in the bottom status bar. + This video provides a brief tutorial for each DevTools screen. + [#6554](https://github.com/flutter/devtools/pull/6554) + + ![Link to watch a DevTools tutorial video](/assets/images/docs/tools/devtools/release-notes/images-2.28.3/watch_tutorial_link.png "Link to watch a DevTools tutorial video") + +* Added a workaround to fix copy button functionality in VSCode. - [#6598](https://github.com/flutter/devtools/pull/6598) + +## Performance updates + +* Disable the Raster Stats tool for the Impeller backend + since it is not supported. - [#6616](https://github.com/flutter/devtools/pull/6616) + +## VS Code Sidebar updates + +* When using VS Code with a light theme, the embedded sidebar provided by + DevTools will now also show in the light theme. - [#6581](https://github.com/flutter/devtools/pull/6581) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.3). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.4-src.md b/src/content/tools/devtools/release-notes/release-notes-2.28.4-src.md deleted file mode 100644 index fdb4cc8900c..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.4-src.md +++ /dev/null @@ -1,22 +0,0 @@ -# DevTools 2.28.4 release notes - -The 2.28.4 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -This was a cherry-pick release on top of DevTools 2.28.3. -To learn about the improvements included in DevTools 2.28.3, please read the -[release notes](/tools/devtools/release-notes/release-notes-2.28.3). - -## Inspector updates - -* Added link to package directory documentation, from the inspect settings dialog - [#6825](https://github.com/flutter/devtools/pull/6825) - -* Fixed a bug where widgets owned by the Flutter framework were showing up in the widget tree view - -[#6857](https://github.com/flutter/devtools/pull/6857) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.4). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.4.md b/src/content/tools/devtools/release-notes/release-notes-2.28.4.md index da887f7c316..dc1cba6e3ce 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.4.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.28.4.md @@ -1,7 +1,28 @@ --- +title: DevTools 2.28.4 release notes shortTitle: 2.28.4 release notes +breadcrumb: 2.28.4 description: Release notes for Dart and Flutter DevTools version 2.28.4. showToc: false --- -{% include ./release-notes-2.28.4-src.md %} +The 2.28.4 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +This was a cherry-pick release on top of DevTools 2.28.3. +To learn about the improvements included in DevTools 2.28.3, please read the +[release notes](/tools/devtools/release-notes/release-notes-2.28.3). + +## Inspector updates + +* Added link to package directory documentation, from the inspect settings dialog - [#6825](https://github.com/flutter/devtools/pull/6825) + +* Fixed a bug where widgets owned by the Flutter framework were showing up in the widget tree view - + [#6857](https://github.com/flutter/devtools/pull/6857) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.4). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.5-src.md b/src/content/tools/devtools/release-notes/release-notes-2.28.5-src.md deleted file mode 100644 index 5c5d50ca1dd..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.5-src.md +++ /dev/null @@ -1,25 +0,0 @@ -# DevTools 2.28.5 release notes - -The 2.28.5 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -This was a cherry-pick release on top of DevTools 2.28.4. -To learn about the improvements included in DevTools 2.28.4, please read the -[release notes](/tools/devtools/release-notes/release-notes-2.28.4). - -## Inspector updates - -* Only cache pub root directories added by the user. - [#6897](https://github.com/flutter/devtools/pull/6897) - -* Remove Flutter pub root if it was accidently cached. - [#6911](https://github.com/flutter/devtools/pull/6911) - -## DevTools Extension updates - -* Fixed a couple bugs preventing Dart server apps from connecting to DevTools extensions. - [#6982](https://github.com/flutter/devtools/pull/6982), [#6993](https://github.com/flutter/devtools/pull/6993) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.5). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.28.5.md b/src/content/tools/devtools/release-notes/release-notes-2.28.5.md index 562336a86c9..b370b2f7cc5 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.28.5.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.28.5.md @@ -1,7 +1,31 @@ --- +title: DevTools 2.28.5 release notes shortTitle: 2.28.5 release notes +breadcrumb: 2.28.5 description: Release notes for Dart and Flutter DevTools version 2.28.5. showToc: false --- -{% include ./release-notes-2.28.5-src.md %} +The 2.28.5 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +This was a cherry-pick release on top of DevTools 2.28.4. +To learn about the improvements included in DevTools 2.28.4, please read the +[release notes](/tools/devtools/release-notes/release-notes-2.28.4). + +## Inspector updates + +* Only cache pub root directories added by the user. - [#6897](https://github.com/flutter/devtools/pull/6897) + +* Remove Flutter pub root if it was accidently cached. - [#6911](https://github.com/flutter/devtools/pull/6911) + +## DevTools Extension updates + +* Fixed a couple bugs preventing Dart server apps from connecting to DevTools extensions. - [#6982](https://github.com/flutter/devtools/pull/6982), [#6993](https://github.com/flutter/devtools/pull/6993) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.28.5). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.29.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.29.0-src.md deleted file mode 100644 index 0e41cf61d2a..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.29.0-src.md +++ /dev/null @@ -1,52 +0,0 @@ -# DevTools 2.29.0 release notes - -The 2.29.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Fix a bug with service extension states not - being cleared on app disconnect. - [#6547](https://github.com/flutter/devtools/pull/6547) - -* Improved styling of bottom status bar when connected to an app. - [#6525](https://github.com/flutter/devtools/pull/6525) - -* Added a workaround to fix copy button functionality in VSCode. - [#6598](https://github.com/flutter/devtools/pull/6598) - -## Performance updates - -* Added an option in the "Enhance Tracing" menu for tracking platform channel - activity. This is useful for apps with plugins. - [#6515](https://github.com/flutter/devtools/pull/6515) - - ![Track platform channels setting](/assets/images/docs/tools/devtools/release-notes/images-2.29.0/track_platform_channels.png "Track platform channels setting") - -* Made the Performance screen available when there is no connected app. - Performance data that was previously saved from DevTools can be - reloaded for viewing from this screen. - [#6567](https://github.com/flutter/devtools/pull/6567) - -* Added an "Open" button to the Performance controls for - loading data that was previously saved from DevTools. - [#6567](https://github.com/flutter/devtools/pull/6567) - - ![Open file button on the performance screen](/assets/images/docs/tools/devtools/release-notes/images-2.29.0/open_file_performance_screen.png "Open file button on the performance screen") - -## CPU profiler updates - -* Tree guidelines are now always enabled for the - "Bottom Up" and "Call Tree" tabs. - [#6534](https://github.com/flutter/devtools/pull/6534) - -* Made the CPU profiler screen available when there is no connected app. - CPU profiles that were previously saved from DevTools can be - reloaded for viewing from this screen. - [#6567](https://github.com/flutter/devtools/pull/6567) - -* Added an "Open" button to the CPU profiler controls for loading data that - was previously saved from DevTools. - [#6567](https://github.com/flutter/devtools/pull/6567) - -## Network profiler updates - -* Network statuses now show with an error color when the request failed. - [#6527](https://github.com/flutter/devtools/pull/6527) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.29.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.29.0.md b/src/content/tools/devtools/release-notes/release-notes-2.29.0.md index 801deccacec..41f0ccff6a6 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.29.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.29.0.md @@ -1,7 +1,58 @@ --- +title: DevTools 2.29.0 release notes shortTitle: 2.29.0 release notes +breadcrumb: 2.29.0 description: Release notes for Dart and Flutter DevTools version 2.29.0. showToc: false --- -{% include ./release-notes-2.29.0-src.md %} +The 2.29.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Fix a bug with service extension states not + being cleared on app disconnect. - [#6547](https://github.com/flutter/devtools/pull/6547) + +* Improved styling of bottom status bar when connected to an app. - [#6525](https://github.com/flutter/devtools/pull/6525) + +* Added a workaround to fix copy button functionality in VSCode. - [#6598](https://github.com/flutter/devtools/pull/6598) + +## Performance updates + +* Added an option in the "Enhance Tracing" menu for tracking platform channel + activity. This is useful for apps with plugins. - [#6515](https://github.com/flutter/devtools/pull/6515) + + ![Track platform channels setting](/assets/images/docs/tools/devtools/release-notes/images-2.29.0/track_platform_channels.png "Track platform channels setting") + +* Made the Performance screen available when there is no connected app. + Performance data that was previously saved from DevTools can be + reloaded for viewing from this screen. - [#6567](https://github.com/flutter/devtools/pull/6567) + +* Added an "Open" button to the Performance controls for + loading data that was previously saved from DevTools. - [#6567](https://github.com/flutter/devtools/pull/6567) + + ![Open file button on the performance screen](/assets/images/docs/tools/devtools/release-notes/images-2.29.0/open_file_performance_screen.png "Open file button on the performance screen") + +## CPU profiler updates + +* Tree guidelines are now always enabled for the + "Bottom Up" and "Call Tree" tabs. - [#6534](https://github.com/flutter/devtools/pull/6534) + +* Made the CPU profiler screen available when there is no connected app. + CPU profiles that were previously saved from DevTools can be + reloaded for viewing from this screen. - [#6567](https://github.com/flutter/devtools/pull/6567) + +* Added an "Open" button to the CPU profiler controls for loading data that + was previously saved from DevTools. - [#6567](https://github.com/flutter/devtools/pull/6567) + +## Network profiler updates + +* Network statuses now show with an error color when the request failed. - [#6527](https://github.com/flutter/devtools/pull/6527) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.29.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.30.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.30.0-src.md deleted file mode 100644 index e5cc23a3ada..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.30.0-src.md +++ /dev/null @@ -1,32 +0,0 @@ -# DevTools 2.30.0 release notes - -The 2.30.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## Performance updates - -* Add an indicator of the rendering engine to the Flutter Frames chart. - - [#6771](https://github.com/flutter/devtools/pull/6771) - - ![Flutter rendering engine text](/assets/images/docs/tools/devtools/release-notes/images-2.30.0/flutter_frames_engine_text.png "Text describing the current flutter rendering engine") - -* Improve messaging when we do not have analysis data available for a - Flutter frame. - [#6768](https://github.com/flutter/devtools/pull/6768) - -## VS Code Sidebar updates - -* The Flutter Sidebar provided to VS Code now has the ability to enable new - platforms if a device is available for a platform that is not enabled for - the current project. This also requires a corresponding Dart extension for - VS Code update to appear. - [#6688](https://github.com/flutter/devtools/pull/6688) - -* The DevTools menu in the sidebar now has an entry "Open in Browser" - that opens DevTools in an external browser window even when VS Code settings - are set to usually use embedded DevTools. - [#6736](https://github.com/flutter/devtools/pull/6736) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.30.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.30.0.md b/src/content/tools/devtools/release-notes/release-notes-2.30.0.md index 88e8131621c..55a87010592 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.30.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.30.0.md @@ -1,7 +1,38 @@ --- +title: DevTools 2.30.0 release notes shortTitle: 2.30.0 release notes +breadcrumb: 2.30.0 description: Release notes for Dart and Flutter DevTools version 2.30.0. showToc: false --- -{% include ./release-notes-2.30.0-src.md %} +The 2.30.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## Performance updates + +* Add an indicator of the rendering engine to the Flutter Frames chart. - + [#6771](https://github.com/flutter/devtools/pull/6771) + + ![Flutter rendering engine text](/assets/images/docs/tools/devtools/release-notes/images-2.30.0/flutter_frames_engine_text.png "Text describing the current flutter rendering engine") + +* Improve messaging when we do not have analysis data available for a + Flutter frame. - [#6768](https://github.com/flutter/devtools/pull/6768) + +## VS Code Sidebar updates + +* The Flutter Sidebar provided to VS Code now has the ability to enable new + platforms if a device is available for a platform that is not enabled for + the current project. This also requires a corresponding Dart extension for + VS Code update to appear. - [#6688](https://github.com/flutter/devtools/pull/6688) + +* The DevTools menu in the sidebar now has an entry "Open in Browser" + that opens DevTools in an external browser window even when VS Code settings + are set to usually use embedded DevTools. - [#6736](https://github.com/flutter/devtools/pull/6736) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.30.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.31.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.31.0-src.md deleted file mode 100644 index e91173ea210..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.31.0-src.md +++ /dev/null @@ -1,62 +0,0 @@ -# DevTools 2.31.0 release notes - -The 2.31.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Added a new feature for deep link validation, - supporting deep link web checks on Android. - [#6935](https://github.com/flutter/devtools/pull/6935) -* Added the basic plumbing to allow connections to a Dart Tooling Daemon. - [#7009](https://github.com/flutter/devtools/pull/7009) -* Made table text selectable [#6919](https://github.com/flutter/devtools/pull/6919) - -## Inspector updates - -* When done typing in the search field, the - next selection is now automatically selected - [#6677](https://github.com/flutter/devtools/pull/6677) -* Added link to package directory documentation, - from the inspect settings dialog - [#6825](https://github.com/flutter/devtools/pull/6825) - - ![Link to documentation](/assets/images/docs/tools/devtools/release-notes/images-2.31.0/link-to-doc.png "Link to documentation") - -* Fix bug where widgets owned by the Flutter framework were - showing up in the widget tree view - [#6857](https://github.com/flutter/devtools/pull/6857) -* Only cache pub root directories added by the user - [#6897](https://github.com/flutter/devtools/pull/6897) -* Remove Flutter pub root if it was accidentally cached - [#6911](https://github.com/flutter/devtools/pull/6911) - -## Performance updates - -* Changed raster layer preview background to a checkerboard. - [#6827](https://github.com/flutter/devtools/pull/6827) - -## CPU profiler updates - -* Added hover cards to show sampling rate for the item in drop down. - [#7010](https://github.com/flutter/devtools/pull/7010) - - ![Sampling rate for dropdown](/assets/images/docs/tools/devtools/release-notes/images-2.31.0/hover-for-dropdown.png "Sampling rate for dropdown") - -## Debugger updates - -* Highlight `extension type` as a declaration keyword, - highlight the `$` in identifier interpolation as part of the interpolation, - and properly highlight comments within type arguments. - [6837](https://github.com/flutter/devtools/pull/6837) - -## Logging updates - -* Added scrollbar to details pane. - [#6917](https://github.com/flutter/devtools/pull/6917) - -## VS Code Sidebar updates - -* Fixed an issue that prevented the VS code sidebar from - loading in recent beta/master builds. - [#6984](https://github.com/flutter/devtools/pull/6984) - -## DevTools Extension updates - -* Fixed a couple bugs preventing Dart server apps from - connecting to DevTools extensions. - [#6982](https://github.com/flutter/devtools/pull/6982), [#6993](https://github.com/flutter/devtools/pull/6993) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.31.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.31.0.md b/src/content/tools/devtools/release-notes/release-notes-2.31.0.md index 1fe9b748aaf..3532b3fbcdf 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.31.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.31.0.md @@ -1,7 +1,68 @@ --- +title: DevTools 2.31.0 release notes shortTitle: 2.31.0 release notes +breadcrumb: 2.31.0 description: Release notes for Dart and Flutter DevTools version 2.31.0. showToc: false --- -{% include ./release-notes-2.31.0-src.md %} +The 2.31.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Added a new feature for deep link validation, + supporting deep link web checks on Android. - [#6935](https://github.com/flutter/devtools/pull/6935) +* Added the basic plumbing to allow connections to a Dart Tooling Daemon. - [#7009](https://github.com/flutter/devtools/pull/7009) +* Made table text selectable [#6919](https://github.com/flutter/devtools/pull/6919) + +## Inspector updates + +* When done typing in the search field, the + next selection is now automatically selected - [#6677](https://github.com/flutter/devtools/pull/6677) +* Added link to package directory documentation, + from the inspect settings dialog - [#6825](https://github.com/flutter/devtools/pull/6825) + + ![Link to documentation](/assets/images/docs/tools/devtools/release-notes/images-2.31.0/link-to-doc.png "Link to documentation") + +* Fix bug where widgets owned by the Flutter framework were + showing up in the widget tree view - [#6857](https://github.com/flutter/devtools/pull/6857) +* Only cache pub root directories added by the user - [#6897](https://github.com/flutter/devtools/pull/6897) +* Remove Flutter pub root if it was accidentally cached - [#6911](https://github.com/flutter/devtools/pull/6911) + +## Performance updates + +* Changed raster layer preview background to a checkerboard. - [#6827](https://github.com/flutter/devtools/pull/6827) + +## CPU profiler updates + +* Added hover cards to show sampling rate for the item in drop down. - [#7010](https://github.com/flutter/devtools/pull/7010) + + ![Sampling rate for dropdown](/assets/images/docs/tools/devtools/release-notes/images-2.31.0/hover-for-dropdown.png "Sampling rate for dropdown") + +## Debugger updates + +* Highlight `extension type` as a declaration keyword, + highlight the `$` in identifier interpolation as part of the interpolation, + and properly highlight comments within type arguments. - [6837](https://github.com/flutter/devtools/pull/6837) + +## Logging updates + +* Added scrollbar to details pane. - [#6917](https://github.com/flutter/devtools/pull/6917) + +## VS Code Sidebar updates + +* Fixed an issue that prevented the VS code sidebar from + loading in recent beta/master builds. - [#6984](https://github.com/flutter/devtools/pull/6984) + +## DevTools Extension updates + +* Fixed a couple bugs preventing Dart server apps from + connecting to DevTools extensions. - [#6982](https://github.com/flutter/devtools/pull/6982), [#6993](https://github.com/flutter/devtools/pull/6993) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.31.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.32.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.32.0-src.md deleted file mode 100644 index b517d3b7a30..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.32.0-src.md +++ /dev/null @@ -1,59 +0,0 @@ -# DevTools 2.32.0 release notes - -The 2.32.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Improved overall usability by making the DevTools UI more dense. - This significantly improves the user experience when using - DevTools embedded in an IDE. - [#7030](https://github.com/flutter/devtools/pull/7030) -* Removed the "Dense mode" setting. - [#7086](https://github.com/flutter/devtools/pull/7086) -* Added support for filtering with regular expressions in the - Logging, Network, and CPU profiler pages - [#7027](https://github.com/flutter/devtools/pull/7027) -* Add a DevTools server interaction for getting the DTD uri. - [#7054](https://github.com/flutter/devtools/pull/7054) - -## Memory updates - -* Supported allocation tracing for Flutter profile builds and - Dart AOT compiled applications. - [#7058](https://github.com/flutter/devtools/pull/7058) -* Supported import of memory snapshots. - [#6974](https://github.com/flutter/devtools/pull/6974) - -## Debugger updates - -* Highlighted `extension type` as a declaration keyword, - highlight the `$` in identifier interpolation as part of the interpolation, - and properly highlight comments within type arguments. - [#6837](https://github.com/flutter/devtools/pull/6837) - -## Logging updates - -* Added toggle filters to filter out noisy Flutter and Dart logs - [#7026](https://github.com/flutter/devtools/pull/7026) - - ![Logging view filters](/assets/images/docs/tools/devtools/release-notes/images-2.32.0/logging_toggle_filters.png "Toggle filters for logging screen") - -* Added a scrollbar to the details pane. - [#6917](https://github.com/flutter/devtools/pull/6917) - -## DevTools extension updates - -* Added a description and documentation link to the `devtools_options.yaml` file - that is created in a user's project. - [#7052](https://github.com/flutter/devtools/pull/7052) -* Updated the Simulated DevTools Environment Panel to be collapsible - (thanks to @victoreronmosele!) - [#7062](https://github.com/flutter/devtools/pull/7062) -* Integrated DevTools extensions with the new Dart Tooling Daemon. - This will allow DevTools extensions to access public methods registered by - other DTD clients, such as an IDE, as well as access a minimal file system API - for interacting with the development project. - [#7108](https://github.com/flutter/devtools/pull/7108) - -## VS Code sidebar updates - -* Fixed an issue that prevented the VS code sidebar from - loading in recent `beta` and `main` builds. - [#6984](https://github.com/flutter/devtools/pull/6984) -* Showed DevTools extensions as an option from the - debug sessions DevTools dropdown, when available. [#6709](https://github.com/flutter/devtools/pull/6709) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.32.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.32.0.md b/src/content/tools/devtools/release-notes/release-notes-2.32.0.md index c35cc61feba..d5e0d47fef3 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.32.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.32.0.md @@ -1,7 +1,65 @@ --- +title: DevTools 2.32.0 release notes shortTitle: 2.32.0 release notes +breadcrumb: 2.32.0 description: Release notes for Dart and Flutter DevTools version 2.32.0. showToc: false --- -{% include ./release-notes-2.32.0-src.md %} +The 2.32.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Improved overall usability by making the DevTools UI more dense. + This significantly improves the user experience when using + DevTools embedded in an IDE. - [#7030](https://github.com/flutter/devtools/pull/7030) +* Removed the "Dense mode" setting. - [#7086](https://github.com/flutter/devtools/pull/7086) +* Added support for filtering with regular expressions in the + Logging, Network, and CPU profiler pages - [#7027](https://github.com/flutter/devtools/pull/7027) +* Add a DevTools server interaction for getting the DTD uri. - [#7054](https://github.com/flutter/devtools/pull/7054) + +## Memory updates + +* Supported allocation tracing for Flutter profile builds and + Dart AOT compiled applications. - [#7058](https://github.com/flutter/devtools/pull/7058) +* Supported import of memory snapshots. - [#6974](https://github.com/flutter/devtools/pull/6974) + +## Debugger updates + +* Highlighted `extension type` as a declaration keyword, + highlight the `$` in identifier interpolation as part of the interpolation, + and properly highlight comments within type arguments. - [#6837](https://github.com/flutter/devtools/pull/6837) + +## Logging updates + +* Added toggle filters to filter out noisy Flutter and Dart logs - [#7026](https://github.com/flutter/devtools/pull/7026) + + ![Logging view filters](/assets/images/docs/tools/devtools/release-notes/images-2.32.0/logging_toggle_filters.png "Toggle filters for logging screen") + +* Added a scrollbar to the details pane. - [#6917](https://github.com/flutter/devtools/pull/6917) + +## DevTools extension updates + +* Added a description and documentation link to the `devtools_options.yaml` file + that is created in a user's project. - [#7052](https://github.com/flutter/devtools/pull/7052) +* Updated the Simulated DevTools Environment Panel to be collapsible + (thanks to @victoreronmosele!) - [#7062](https://github.com/flutter/devtools/pull/7062) +* Integrated DevTools extensions with the new Dart Tooling Daemon. + This will allow DevTools extensions to access public methods registered by + other DTD clients, such as an IDE, as well as access a minimal file system API + for interacting with the development project. - [#7108](https://github.com/flutter/devtools/pull/7108) + +## VS Code sidebar updates + +* Fixed an issue that prevented the VS code sidebar from + loading in recent `beta` and `main` builds. - [#6984](https://github.com/flutter/devtools/pull/6984) +* Showed DevTools extensions as an option from the + debug sessions DevTools dropdown, when available. [#6709](https://github.com/flutter/devtools/pull/6709) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.32.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.33.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.33.0-src.md deleted file mode 100644 index ac310bdb8e8..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.33.0-src.md +++ /dev/null @@ -1,56 +0,0 @@ -# DevTools 2.33.0 release notes - -The 2.33.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools). - -## General updates - -* Improved overall usability by making the DevTools UI more dense. - This significantly improves the user experience when using - DevTools embedded in an IDE. - [#7030](https://github.com/flutter/devtools/pull/7030) -* Removed the "Dense mode" setting. - [#7086](https://github.com/flutter/devtools/pull/7086) -* Added support for filtering with regular expressions in - the Logging, Network, and CPU profiler pages. - [#7027](https://github.com/flutter/devtools/pull/7027) -* Add a DevTools server interaction for getting the DTD URI. - [#7054](https://github.com/flutter/devtools/pull/7054), [#7164](https://github.com/flutter/devtools/pull/7164) -* Enabled expression evaluation with scope for the web, - allowing evaluation of inspected widgets. - [#7144](https://github.com/flutter/devtools/pull/7144) -* Update `package:vm_service` constraint to `^14.0.0`. - [#6953](https://github.com/flutter/devtools/pull/6953) -* Onboarding DevTools to [`package:unified_analytics`](https://pub.dev/packages/unified_analytics) for - unified telemetry logging across Flutter and Dart tooling. - [#7084](https://github.com/flutter/devtools/pull/7084) - -## Debugger updates - -* Fixed off by one error causing profiler hits to be - rendered on the wrong lines. - [#7178](https://github.com/flutter/devtools/pull/7178) -* Improved contrast of line numbers when - displaying code coverage hits in dark mode. - [#7178](https://github.com/flutter/devtools/pull/7178) -* Improved contrast of profiling details when - displaying profiler hits in dark mode. - [#7178](https://github.com/flutter/devtools/pull/7178) -* Fixed syntax highlighting for comments when - the source file uses `\r\n` line endings [#7190](https://github.com/flutter/devtools/pull/7190) -* Re-establish breakpoints after a hot-restart. - [#7205](https://github.com/flutter/devtools/pull/7205) - -## VS Code Sidebar updates - -* Do not show DevTools release notes in the Flutter sidebar. - [#7166](https://github.com/flutter/devtools/pull/7166) - -## DevTools Extension updates - -* Added support for connecting to the Dart Tooling Daemon from - the simulated DevTools environment. - [#7133](https://github.com/flutter/devtools/pull/7133) -* Added help buttons to the VM Service and DTD connection text fields in - the simulated DevTools environment. - [#7133](https://github.com/flutter/devtools/pull/7133) -* Fixed an issue with not detecting extensions for - test files in subdirectories. - [#7174](https://github.com/flutter/devtools/pull/7174) -* Added an example of creating an extension for a pure Dart package. - [#7196](https://github.com/flutter/devtools/pull/7196) -* Updated the `README.md` and `example/README.md` with - more complete documentation. - [#7237](https://github.com/flutter/devtools/pull/7237), [#7261](https://github.com/flutter/devtools/pull/7261) -* Added a `devtools_extensions validate` command to - validate extension requirements during development. - [#7257](https://github.com/flutter/devtools/pull/7257) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.33.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.33.0.md b/src/content/tools/devtools/release-notes/release-notes-2.33.0.md index 35b3f7e138b..622cc376a40 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.33.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.33.0.md @@ -1,7 +1,62 @@ --- +title: DevTools 2.33.0 release notes shortTitle: 2.33.0 release notes +breadcrumb: 2.33.0 description: Release notes for Dart and Flutter DevTools version 2.33.0. showToc: false --- -{% include ./release-notes-2.33.0-src.md %} +The 2.33.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools). + +## General updates + +* Improved overall usability by making the DevTools UI more dense. + This significantly improves the user experience when using + DevTools embedded in an IDE. - [#7030](https://github.com/flutter/devtools/pull/7030) +* Removed the "Dense mode" setting. - [#7086](https://github.com/flutter/devtools/pull/7086) +* Added support for filtering with regular expressions in + the Logging, Network, and CPU profiler pages. - [#7027](https://github.com/flutter/devtools/pull/7027) +* Add a DevTools server interaction for getting the DTD URI. - [#7054](https://github.com/flutter/devtools/pull/7054), [#7164](https://github.com/flutter/devtools/pull/7164) +* Enabled expression evaluation with scope for the web, + allowing evaluation of inspected widgets. - [#7144](https://github.com/flutter/devtools/pull/7144) +* Update `package:vm_service` constraint to `^14.0.0`. - [#6953](https://github.com/flutter/devtools/pull/6953) +* Onboarding DevTools to [`package:unified_analytics`](https://pub.dev/packages/unified_analytics) for + unified telemetry logging across Flutter and Dart tooling. - [#7084](https://github.com/flutter/devtools/pull/7084) + +## Debugger updates + +* Fixed off by one error causing profiler hits to be + rendered on the wrong lines. - [#7178](https://github.com/flutter/devtools/pull/7178) +* Improved contrast of line numbers when + displaying code coverage hits in dark mode. - [#7178](https://github.com/flutter/devtools/pull/7178) +* Improved contrast of profiling details when + displaying profiler hits in dark mode. - [#7178](https://github.com/flutter/devtools/pull/7178) +* Fixed syntax highlighting for comments when + the source file uses `\r\n` line endings [#7190](https://github.com/flutter/devtools/pull/7190) +* Re-establish breakpoints after a hot-restart. - [#7205](https://github.com/flutter/devtools/pull/7205) + +## VS Code Sidebar updates + +* Do not show DevTools release notes in the Flutter sidebar. - [#7166](https://github.com/flutter/devtools/pull/7166) + +## DevTools Extension updates + +* Added support for connecting to the Dart Tooling Daemon from + the simulated DevTools environment. - [#7133](https://github.com/flutter/devtools/pull/7133) +* Added help buttons to the VM Service and DTD connection text fields in + the simulated DevTools environment. - [#7133](https://github.com/flutter/devtools/pull/7133) +* Fixed an issue with not detecting extensions for + test files in subdirectories. - [#7174](https://github.com/flutter/devtools/pull/7174) +* Added an example of creating an extension for a pure Dart package. - [#7196](https://github.com/flutter/devtools/pull/7196) +* Updated the `README.md` and `example/README.md` with + more complete documentation. - [#7237](https://github.com/flutter/devtools/pull/7237), [#7261](https://github.com/flutter/devtools/pull/7261) +* Added a `devtools_extensions validate` command to + validate extension requirements during development. - [#7257](https://github.com/flutter/devtools/pull/7257) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.33.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.34.1-src.md b/src/content/tools/devtools/release-notes/release-notes-2.34.1-src.md deleted file mode 100644 index 13bd524ace7..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.34.1-src.md +++ /dev/null @@ -1,71 +0,0 @@ -# DevTools 2.34.1 release notes - -The 2.34.1 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools). - -## General updates - -* Fixed an issue preventing DevTools from connecting to Flutter apps that - are not launched from Flutter Tools. - [#6848](https://github.com/flutter/devtools/issues/6848) -* Improved performance of the FlatTable. - - [#7391](https://github.com/flutter/devtools/pull/7391) - -## Inspector updates - -- Fixes an edge case where widgets from other packages could - show up in the inspector tree. - [#7353](https://github.com/flutter/devtools/pull/7353) - -## Performance updates -* Add a setting to include CPU samples in the Timeline. - - [#7333](https://github.com/flutter/devtools/pull/7333), [#7369](https://github.com/flutter/devtools/pull/7369) - - ![Timeline settings](/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7369-timeline-settings.png "Timeline settings") - -* Removed the legacy trace viewer. - The legacy trace viewer was replaced with the - embedded Perfetto trace viewer in DevTools version 2.21.1, but was - available behind a setting to ensure a smooth rollout. - This release of DevTools removes the legacy trace viewer entirely. - [#7316](https://github.com/flutter/devtools/pull/7316) -* Updated the Perfetto trace viewer build. - - [#7445](https://github.com/flutter/devtools/pull/7445), - [#7456](https://github.com/flutter/devtools/pull/7456), - [#7480](https://github.com/flutter/devtools/pull/7480) -* Added a loading message to show when refreshing the timeline. - [#7463](https://github.com/flutter/devtools/pull/7463) - - ![Loading message](/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7463-overlay.png "Loading message") - -## Memory updates - -* Enabled export of snapshots and improved snapshotting performance. - - [#7197](https://github.com/flutter/devtools/pull/7197), - [#7439](https://github.com/flutter/devtools/pull/7439), - [#7449](https://github.com/flutter/devtools/pull/7449) - - ![Export snapshot](/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7197-export.png "Export snapshot") - -* Fixed failures during disconnect in tracing. - [#7440](https://github.com/flutter/devtools/pull/7440) - -* Made class filter shared between - the panes `Profile Memory` and `Diff Snapshots`. - [#7462](https://github.com/flutter/devtools/pull/7462) - -## Network profiler updates - -* Improved Network profiler performance. - [#7266](https://github.com/flutter/devtools/pull/7266) -* Fixed a bug where selected pending requests weren't - refreshing the tab once updated. - [#7266](https://github.com/flutter/devtools/pull/7266) -* Fixed the JSON viewer so multiline strings are visible in their row, and - through a tooltip. - [#7389](https://github.com/flutter/devtools/pull/7389) -* Fixed JsonViewer where all of the - expanded sections would snap closed. [#7367](https://github.com/flutter/devtools/pull/7367) - -## Deep Links tool updates - -* Automatically populate a list of Flutter projects from - the connected IDE. - [#7415](https://github.com/flutter/devtools/pull/7415), [#7431](https://github.com/flutter/devtools/pull/7431) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.34.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.34.1.md b/src/content/tools/devtools/release-notes/release-notes-2.34.1.md index e17f7a2bf6c..7bc3c4e9e01 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.34.1.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.34.1.md @@ -1,7 +1,77 @@ --- +title: DevTools 2.34.1 release notes shortTitle: 2.34.1 release notes +breadcrumb: 2.34.1 description: Release notes for Dart and Flutter DevTools version 2.34.1. showToc: false --- -{% include ./release-notes-2.34.1-src.md %} +The 2.34.1 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools). + +## General updates + +* Fixed an issue preventing DevTools from connecting to Flutter apps that + are not launched from Flutter Tools. - [#6848](https://github.com/flutter/devtools/issues/6848) +* Improved performance of the FlatTable. - + [#7391](https://github.com/flutter/devtools/pull/7391) + +## Inspector updates + +- Fixes an edge case where widgets from other packages could + show up in the inspector tree. - [#7353](https://github.com/flutter/devtools/pull/7353) + +## Performance updates +* Add a setting to include CPU samples in the Timeline. - + [#7333](https://github.com/flutter/devtools/pull/7333), [#7369](https://github.com/flutter/devtools/pull/7369) + + ![Timeline settings](/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7369-timeline-settings.png "Timeline settings") + +* Removed the legacy trace viewer. + The legacy trace viewer was replaced with the + embedded Perfetto trace viewer in DevTools version 2.21.1, but was + available behind a setting to ensure a smooth rollout. + This release of DevTools removes the legacy trace viewer entirely. - [#7316](https://github.com/flutter/devtools/pull/7316) +* Updated the Perfetto trace viewer build. - + [#7445](https://github.com/flutter/devtools/pull/7445), + [#7456](https://github.com/flutter/devtools/pull/7456), + [#7480](https://github.com/flutter/devtools/pull/7480) +* Added a loading message to show when refreshing the timeline. - [#7463](https://github.com/flutter/devtools/pull/7463) + + ![Loading message](/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7463-overlay.png "Loading message") + +## Memory updates + +* Enabled export of snapshots and improved snapshotting performance. - + [#7197](https://github.com/flutter/devtools/pull/7197), + [#7439](https://github.com/flutter/devtools/pull/7439), + [#7449](https://github.com/flutter/devtools/pull/7449) + + ![Export snapshot](/assets/images/docs/tools/devtools/release-notes/images-2.34.1/7197-export.png "Export snapshot") + +* Fixed failures during disconnect in tracing. - [#7440](https://github.com/flutter/devtools/pull/7440) + +* Made class filter shared between + the panes `Profile Memory` and `Diff Snapshots`. - [#7462](https://github.com/flutter/devtools/pull/7462) + +## Network profiler updates + +* Improved Network profiler performance. - [#7266](https://github.com/flutter/devtools/pull/7266) +* Fixed a bug where selected pending requests weren't + refreshing the tab once updated. - [#7266](https://github.com/flutter/devtools/pull/7266) +* Fixed the JSON viewer so multiline strings are visible in their row, and + through a tooltip. - [#7389](https://github.com/flutter/devtools/pull/7389) +* Fixed JsonViewer where all of the + expanded sections would snap closed. [#7367](https://github.com/flutter/devtools/pull/7367) + +## Deep Links tool updates + +* Automatically populate a list of Flutter projects from + the connected IDE. - [#7415](https://github.com/flutter/devtools/pull/7415), [#7431](https://github.com/flutter/devtools/pull/7431) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.34.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.35.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.35.0-src.md deleted file mode 100644 index 7d3c3853c12..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.35.0-src.md +++ /dev/null @@ -1,64 +0,0 @@ -# DevTools 2.35.0 release notes - -The 2.35.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools). - -## General updates - -* Changed to a single button for starting and stopping - recording on the Network screen and CPU profiler screen. - [#7573](https://github.com/flutter/devtools/pull/7573) - - ![A screen shot of the CPU profiler tab, with the new recording button.](/assets/images/docs/tools/devtools/release-notes/images-2.35.0/profiler_recording.png) - ![A screen shot of the network tab, with the new recording button.](/assets/images/docs/tools/devtools/release-notes/images-2.35.0/network_recording.png) - -## Inspector updates - -* Add a preference for the default inspector view - [#6949](https://github.com/flutter/devtools/pull/6949) - -## Memory updates - -* Replaced total size with reachable size in snapshot list. - [#7493](https://github.com/flutter/devtools/pull/7493) - -## Debugger updates - -* During a hot-restart, `pause_isolates_on_start` and only - `resume` the app once breakpoints are set. - [#7234](https://github.com/flutter/devtools/pull/7234) - -## Network profiler updates - -* Added text selection in text viewer for requests and responses. - [#7596](https://github.com/flutter/devtools/pull/7596) -* Added a JSON copy experience to the JSON viewer. - [#7596](https://github.com/flutter/devtools/pull/7596) - - ![The new JSON copy experience in the JSON viewer](/assets/images/docs/tools/devtools/release-notes/images-2.35.0/json_viewer_copy.png) - -* Fixed a bug where stopping and starting network recording listed requests that - happened while not recording. - [#7626](https://github.com/flutter/devtools/pull/7626) - -## Deep links tool updates - -* Improve layout for narrow screens. - [#7524](https://github.com/flutter/devtools/pull/7524) -* Add error handling for missing schemes and domains - [#7559](https://github.com/flutter/devtools/pull/7559) - -## VS Code Sidebar updates - -* Added a DevTools section with a list of tools and extensions that - are available without a debug session. - - [#7598](https://github.com/flutter/devtools/pull/7598), [#7604](https://github.com/flutter/devtools/pull/7604) - -## DevTools Extension updates - -* Support DevTools extensions that do not require a running app, and - detect them from the user's IDE workspace. - [#7612](https://github.com/flutter/devtools/pull/7612) -* Deprecate the `DevToolsExtension.requiresRunningApplication` field in - favor of the new optional `requiresConnection` field that - can be added to an extension's `config.yaml` file. - - [#7611](https://github.com/flutter/devtools/pull/7611), [#7602](https://github.com/flutter/devtools/pull/7602) -* Detect extensions for all types of run targets in a package. - - [#7533](https://github.com/flutter/devtools/pull/7533), [#7535](https://github.com/flutter/devtools/pull/7535) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.35.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.35.0.md b/src/content/tools/devtools/release-notes/release-notes-2.35.0.md index be99873e1b3..8409590c12b 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.35.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.35.0.md @@ -1,7 +1,70 @@ --- +title: DevTools 2.35.0 release notes shortTitle: 2.35.0 release notes +breadcrumb: 2.35.0 description: Release notes for Dart and Flutter DevTools version 2.35.0. showToc: false --- -{% include ./release-notes-2.35.0-src.md %} +The 2.35.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools). + +## General updates + +* Changed to a single button for starting and stopping + recording on the Network screen and CPU profiler screen. - [#7573](https://github.com/flutter/devtools/pull/7573) + + ![A screen shot of the CPU profiler tab, with the new recording button.](/assets/images/docs/tools/devtools/release-notes/images-2.35.0/profiler_recording.png) + ![A screen shot of the network tab, with the new recording button.](/assets/images/docs/tools/devtools/release-notes/images-2.35.0/network_recording.png) + +## Inspector updates + +* Add a preference for the default inspector view - [#6949](https://github.com/flutter/devtools/pull/6949) + +## Memory updates + +* Replaced total size with reachable size in snapshot list. - [#7493](https://github.com/flutter/devtools/pull/7493) + +## Debugger updates + +* During a hot-restart, `pause_isolates_on_start` and only + `resume` the app once breakpoints are set. - [#7234](https://github.com/flutter/devtools/pull/7234) + +## Network profiler updates + +* Added text selection in text viewer for requests and responses. - [#7596](https://github.com/flutter/devtools/pull/7596) +* Added a JSON copy experience to the JSON viewer. - [#7596](https://github.com/flutter/devtools/pull/7596) + + ![The new JSON copy experience in the JSON viewer](/assets/images/docs/tools/devtools/release-notes/images-2.35.0/json_viewer_copy.png) + +* Fixed a bug where stopping and starting network recording listed requests that + happened while not recording. - [#7626](https://github.com/flutter/devtools/pull/7626) + +## Deep links tool updates + +* Improve layout for narrow screens. - [#7524](https://github.com/flutter/devtools/pull/7524) +* Add error handling for missing schemes and domains - [#7559](https://github.com/flutter/devtools/pull/7559) + +## VS Code Sidebar updates + +* Added a DevTools section with a list of tools and extensions that + are available without a debug session. - + [#7598](https://github.com/flutter/devtools/pull/7598), [#7604](https://github.com/flutter/devtools/pull/7604) + +## DevTools Extension updates + +* Support DevTools extensions that do not require a running app, and + detect them from the user's IDE workspace. - [#7612](https://github.com/flutter/devtools/pull/7612) +* Deprecate the `DevToolsExtension.requiresRunningApplication` field in + favor of the new optional `requiresConnection` field that + can be added to an extension's `config.yaml` file. - + [#7611](https://github.com/flutter/devtools/pull/7611), [#7602](https://github.com/flutter/devtools/pull/7602) +* Detect extensions for all types of run targets in a package. - + [#7533](https://github.com/flutter/devtools/pull/7533), [#7535](https://github.com/flutter/devtools/pull/7535) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.35.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.36.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.36.0-src.md deleted file mode 100644 index 31286e934c0..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.36.0-src.md +++ /dev/null @@ -1,51 +0,0 @@ -# DevTools 2.36.0 release notes - -The 2.36.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools). - -## Performance updates - -* Added a feature for showing widget build counts. - Enable this setting to see widget build counts for - each Flutter frame in the "Frame Analysis" tool, or to see - an aggregate summary of these counts in the new "Rebuild Stats" tool. - - [#7838](https://github.com/flutter/devtools/pull/7838), [#7847](https://github.com/flutter/devtools/pull/7847) - - ![Track widget build counts setting](/assets/images/docs/tools/devtools/release-notes/images-2.36.0/track_build_counts_setting.png "Track widget build counts setting") - - ![Widget rebuild counts in the Frame Analysis view](/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_counts_frame_analysis.png "Widget rebuilds counts for a flutter frame") - - ![Widget rebuild counts in the Rebuild Stats view](/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_stats.png "Widget rebuilds counts aggregate stats") - -## Network profiler updates - -* Added better support for narrow viewing windows, like when - this screen is embedded in an IDE. - [#7726](https://github.com/flutter/devtools/pull/7726) - -## Deep links tool updates - -* Adds an error page to explain the issue when - the tool fails to parse the project. - [#7767](https://github.com/flutter/devtools/pull/7767) - -## DevTools Extension updates - -* Fixed an issue with detecting extensions for - Dart or Flutter tests. - [#7717](https://github.com/flutter/devtools/pull/7717) -* Fixed an issue with detecting extensions for - nested Dart or Flutter projects. - [#7742](https://github.com/flutter/devtools/pull/7742) -* Added an example to `package:devtools_extensions` that shows - how to interact with the Dart Tooling Daemon from - a DevTools extension. - [#7752](https://github.com/flutter/devtools/pull/7752) -* Fixed a DevTools routing bug related to - disabling an extension. - [#7791](https://github.com/flutter/devtools/pull/7791) -* Fixed a bug causing a "Page Not Found" error when - refreshing DevTools from an extension screen. - [#7822](https://github.com/flutter/devtools/pull/7822) -* Fixed a theming issue when extensions are - embedded in an IDE - [#7824](https://github.com/flutter/devtools/pull/7824) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.36.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.36.0.md b/src/content/tools/devtools/release-notes/release-notes-2.36.0.md index 922d3401f0b..f4621d962d9 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.36.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.36.0.md @@ -1,7 +1,57 @@ --- +title: DevTools 2.36.0 release notes shortTitle: 2.36.0 release notes +breadcrumb: 2.36.0 description: Release notes for Dart and Flutter DevTools version 2.36.0. showToc: false --- -{% include ./release-notes-2.36.0-src.md %} +The 2.36.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools). + +## Performance updates + +* Added a feature for showing widget build counts. + Enable this setting to see widget build counts for + each Flutter frame in the "Frame Analysis" tool, or to see + an aggregate summary of these counts in the new "Rebuild Stats" tool. - + [#7838](https://github.com/flutter/devtools/pull/7838), [#7847](https://github.com/flutter/devtools/pull/7847) + + ![Track widget build counts setting](/assets/images/docs/tools/devtools/release-notes/images-2.36.0/track_build_counts_setting.png "Track widget build counts setting") + + ![Widget rebuild counts in the Frame Analysis view](/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_counts_frame_analysis.png "Widget rebuilds counts for a flutter frame") + + ![Widget rebuild counts in the Rebuild Stats view](/assets/images/docs/tools/devtools/release-notes/images-2.36.0/rebuild_stats.png "Widget rebuilds counts aggregate stats") + +## Network profiler updates + +* Added better support for narrow viewing windows, like when + this screen is embedded in an IDE. - [#7726](https://github.com/flutter/devtools/pull/7726) + +## Deep links tool updates + +* Adds an error page to explain the issue when + the tool fails to parse the project. - [#7767](https://github.com/flutter/devtools/pull/7767) + +## DevTools Extension updates + +* Fixed an issue with detecting extensions for + Dart or Flutter tests. - [#7717](https://github.com/flutter/devtools/pull/7717) +* Fixed an issue with detecting extensions for + nested Dart or Flutter projects. - [#7742](https://github.com/flutter/devtools/pull/7742) +* Added an example to `package:devtools_extensions` that shows + how to interact with the Dart Tooling Daemon from + a DevTools extension. - [#7752](https://github.com/flutter/devtools/pull/7752) +* Fixed a DevTools routing bug related to + disabling an extension. - [#7791](https://github.com/flutter/devtools/pull/7791) +* Fixed a bug causing a "Page Not Found" error when + refreshing DevTools from an extension screen. - [#7822](https://github.com/flutter/devtools/pull/7822) +* Fixed a theming issue when extensions are + embedded in an IDE - [#7824](https://github.com/flutter/devtools/pull/7824) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.36.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.37.2-src.md b/src/content/tools/devtools/release-notes/release-notes-2.37.2-src.md deleted file mode 100644 index 97a74d482e5..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.37.2-src.md +++ /dev/null @@ -1,44 +0,0 @@ -# DevTools 2.37.2 release notes - -The 2.37.2 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -* Improved messaging when a screen is unavailable for the - platform of the connected app. - [#7958](https://github.com/flutter/devtools/pull/7958) -* Fixed a bug where an infinite spinner was shown upon - app disconnect. - [#7992](https://github.com/flutter/devtools/pull/7992) -* Fixed a bug where trying to reuse a disconnected DevTools instance would - fail. - [#8009](https://github.com/flutter/devtools/pull/8009) - -## Performance updates - -* Removed the "Raster Stats" feature. - This tool did not work for the Impeller rendering engine, and - the information it gave for the SKIA rendering engine was - often misleading and unactionable. Users should follow the - official Flutter guidance for [Performance and optimization](/perf) when - debugging the rendering performance of their Flutter apps. - [#7981](https://github.com/flutter/devtools/pull/7981). - -## Network profiler updates - -* Fixed an issue where socket statistics were being reported as web sockets. - [#8061](https://github.com/flutter/devtools/pull/8061) - - ![Network profiler correctly displaying socket statistics](/assets/images/docs/tools/devtools/release-notes/images-2.37.2/socket-profiling.png "Network profiler correctly displaying socket statistics") - -* Added query parameters to the request details view. - [#7825](https://github.com/flutter/devtools/pull/7825) - -## VS Code Sidebar updates - -* Added buttons for all DevTools tools in the sidebar by default, even when - there are no debug sessions available. - [#7947](https://github.com/flutter/devtools/pull/7947) - - ![DevTools tools in the sidebar](/assets/images/docs/tools/devtools/release-notes/images-2.37.2/devtools_in_sidebar.png) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.37.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.37.2.md b/src/content/tools/devtools/release-notes/release-notes-2.37.2.md index 3c955bfe6ea..c697e00c77b 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.37.2.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.37.2.md @@ -1,7 +1,50 @@ --- +title: DevTools 2.37.2 release notes shortTitle: 2.37.2 release notes +breadcrumb: 2.37.2 description: Release notes for Dart and Flutter DevTools version 2.37.2. showToc: false --- -{% include ./release-notes-2.37.2-src.md %} +The 2.37.2 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +* Improved messaging when a screen is unavailable for the + platform of the connected app. - [#7958](https://github.com/flutter/devtools/pull/7958) +* Fixed a bug where an infinite spinner was shown upon + app disconnect. - [#7992](https://github.com/flutter/devtools/pull/7992) +* Fixed a bug where trying to reuse a disconnected DevTools instance would + fail. - [#8009](https://github.com/flutter/devtools/pull/8009) + +## Performance updates + +* Removed the "Raster Stats" feature. + This tool did not work for the Impeller rendering engine, and + the information it gave for the SKIA rendering engine was + often misleading and unactionable. Users should follow the + official Flutter guidance for [Performance and optimization](/perf) when + debugging the rendering performance of their Flutter apps. - [#7981](https://github.com/flutter/devtools/pull/7981). + +## Network profiler updates + +* Fixed an issue where socket statistics were being reported as web sockets. - [#8061](https://github.com/flutter/devtools/pull/8061) + + ![Network profiler correctly displaying socket statistics](/assets/images/docs/tools/devtools/release-notes/images-2.37.2/socket-profiling.png "Network profiler correctly displaying socket statistics") + +* Added query parameters to the request details view. - [#7825](https://github.com/flutter/devtools/pull/7825) + +## VS Code Sidebar updates + +* Added buttons for all DevTools tools in the sidebar by default, even when + there are no debug sessions available. - [#7947](https://github.com/flutter/devtools/pull/7947) + + ![DevTools tools in the sidebar](/assets/images/docs/tools/devtools/release-notes/images-2.37.2/devtools_in_sidebar.png) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.37.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.38.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.38.0-src.md deleted file mode 100644 index a9fddfca7ee..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.38.0-src.md +++ /dev/null @@ -1,32 +0,0 @@ -# DevTools 2.38.0 release notes - -The 2.38.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## Performance updates - -* Renamed the "Track" builds, paints, and layouts settings to "Trace" -builds, paints, and layouts. - [#8084](https://github.com/flutter/devtools/pull/8084) -* Renamed the "Track widget build counts" setting to "Count widget builds". - [#8084](https://github.com/flutter/devtools/pull/8084) - -## Debugger updates - -* Added recommendation to debug code from an IDE, with links to IDE instructions. - [#8085](https://github.com/flutter/devtools/pull/8085) - -## Network profiler updates - -* Added support to export network requests as a HAR file (thanks to @hrajwade96!). - [#7970](https://github.com/flutter/devtools/pull/7970) - -## DevTools Extension updates - -* Fixed an issue where extensions did not load with the proper theme when -embedded in an IDE. - [#8034](https://github.com/flutter/devtools/pull/8034) -* Added an API for copying text to clipboard by proxy of the parent DevTools web app, which has -workarounds for copy issues when embedded inside an IDE. - [#8130](https://github.com/flutter/devtools/pull/8130) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.38.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.38.0.md b/src/content/tools/devtools/release-notes/release-notes-2.38.0.md index 215f2a5c4f4..a542c2a7d89 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.38.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.38.0.md @@ -1,7 +1,38 @@ --- +title: DevTools 2.38.0 release notes shortTitle: 2.38.0 release notes +breadcrumb: 2.38.0 description: Release notes for Dart and Flutter DevTools version 2.38.0. showToc: false --- -{% include ./release-notes-2.38.0-src.md %} +The 2.38.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## Performance updates + +* Renamed the "Track" builds, paints, and layouts settings to "Trace" + builds, paints, and layouts. - [#8084](https://github.com/flutter/devtools/pull/8084) +* Renamed the "Track widget build counts" setting to "Count widget builds". - [#8084](https://github.com/flutter/devtools/pull/8084) + +## Debugger updates + +* Added recommendation to debug code from an IDE, with links to IDE instructions. - [#8085](https://github.com/flutter/devtools/pull/8085) + +## Network profiler updates + +* Added support to export network requests as a HAR file (thanks to @hrajwade96!). - [#7970](https://github.com/flutter/devtools/pull/7970) + +## DevTools Extension updates + +* Fixed an issue where extensions did not load with the proper theme when + embedded in an IDE. - [#8034](https://github.com/flutter/devtools/pull/8034) +* Added an API for copying text to clipboard by proxy of the parent DevTools web app, which has + workarounds for copy issues when embedded inside an IDE. - [#8130](https://github.com/flutter/devtools/pull/8130) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.38.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.39.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.39.0-src.md deleted file mode 100644 index 87b59dca949..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.39.0-src.md +++ /dev/null @@ -1,31 +0,0 @@ -# DevTools 2.39.0 release notes - -The 2.39.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -* Changed table columns to be sortable by default. - [#8175](https://github.com/flutter/devtools/pull/8175) -* Updated DevTools screen icons to match what is used in the Flutter-supported IDEs. - [#8181](https://github.com/flutter/devtools/pull/8181) - -## Memory updates - -* Enabled offline analysis of memory snapshots, as well as support for viewing memory -data when an app disconnects. For example, this may happen when an app unexpectedly -crashes or hits an out-of-memory issue. - [#7843](https://github.com/flutter/devtools/pull/7843), -[#8093](https://github.com/flutter/devtools/pull/8093), -[#8096](https://github.com/flutter/devtools/pull/8096) - -* Fixed issue where the memory chart could cause the connected application to hit an -out of memory exception while allocating large, short-lived objects repeatedly. - [#8209](https://github.com/flutter/devtools/pull/8209) - -## App size tool updates - -* Added UI polish to the file import views. [#8232](https://github.com/flutter/devtools/pull/8232) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.39.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.39.0.md b/src/content/tools/devtools/release-notes/release-notes-2.39.0.md index e515b193201..db9e339e82d 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.39.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.39.0.md @@ -1,7 +1,37 @@ --- +title: DevTools 2.39.0 release notes shortTitle: 2.39.0 release notes +breadcrumb: 2.39.0 description: Release notes for Dart and Flutter DevTools version 2.39.0. showToc: false --- -{% include ./release-notes-2.39.0-src.md %} +The 2.39.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +* Changed table columns to be sortable by default. - [#8175](https://github.com/flutter/devtools/pull/8175) +* Updated DevTools screen icons to match what is used in the Flutter-supported IDEs. - [#8181](https://github.com/flutter/devtools/pull/8181) + +## Memory updates + +* Enabled offline analysis of memory snapshots, as well as support for viewing memory + data when an app disconnects. For example, this may happen when an app unexpectedly + crashes or hits an out-of-memory issue. - [#7843](https://github.com/flutter/devtools/pull/7843), + [#8093](https://github.com/flutter/devtools/pull/8093), + [#8096](https://github.com/flutter/devtools/pull/8096) + +* Fixed issue where the memory chart could cause the connected application to hit an + out of memory exception while allocating large, short-lived objects repeatedly. - [#8209](https://github.com/flutter/devtools/pull/8209) + +## App size tool updates + +* Added UI polish to the file import views. [#8232](https://github.com/flutter/devtools/pull/8232) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.39.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.40.2-src.md b/src/content/tools/devtools/release-notes/release-notes-2.40.2-src.md deleted file mode 100644 index de1be5ab861..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.40.2-src.md +++ /dev/null @@ -1,67 +0,0 @@ -# DevTools 2.40.2 release notes - -The 2.40.2 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -* Add a setting that allows users to opt in to loading DevTools - with WebAssembly. - [#8270](https://github.com/flutter/devtools/pull/8270) - - ![Wasm opt-in setting](/assets/images/docs/tools/devtools/release-notes/images-2.40.2/wasm_setting.png "DevTools setting to opt into wasm.") - -* Removed the legacy Provider screen from DevTools. - The `package:provider` tool is now distributed as a - DevTools extension from `package:provider`. - Upgrade your `package:provider` dependency to - use the extension. - [#8364](https://github.com/flutter/devtools/pull/8364) - -* Fixed a bug that was causing the DevTools release notes to - always show. - [#8277](https://github.com/flutter/devtools/pull/8277) - -* Added support for loading extensions in pub workspaces - [8347](https://github.com/flutter/devtools/pull/8347). - -* Mapped error stack traces to use the Dart source code locations so - that they are human-readable. - [#8385](https://github.com/flutter/devtools/pull/8385) - -* Added handling for IDE theme change events to - update embedded DevTools UI. - [#8336](https://github.com/flutter/devtools/pull/8336) - -* Fixed a bug that was causing data filters to be cleared when clearing data -on the Network and Logging screens. - [#8407](https://github.com/flutter/devtools/pull/8407) - -* Fixed a bug that was causing the navigator to lose state when opening the VM -Flags dialog. - [#8413](https://github.com/flutter/devtools/pull/8413) - -* Tables match IDE theme when embedded in an IDE. - [#8498](https://github.com/flutter/devtools/pull/8498) - -## Inspector updates - -- Added a setting to the Flutter Inspector controls that - allows users to opt in to the newly redesigned Flutter Inspector. - [#8342](https://github.com/flutter/devtools/pull/8342) - - ![New inspector opt-in setting](/assets/images/docs/tools/devtools/release-notes/images-2.40.2/new_inspector.png "DevTools setting to opt into the new Flutter Inspector.") - -## Performance updates - -* Fixed an issue with the "Refreshing timeline" overlay that was getting shown - when it should not have been. - [#8318](https://github.com/flutter/devtools/pull/8318) - -## Network profiler updates - -* Resolved an issue in `.har` export where - response content was sometimes missing in the data. - [#8333](https://github.com/flutter/devtools/pull/8333) - -## Deep links tool updates - -- Added support for validating iOS deep link settings. - [#8394](https://github.com/flutter/devtools/pull/8394) - - ![Deep link validator for iOS](/assets/images/docs/tools/devtools/release-notes/images-2.40.2/deep_link_ios.png "DevTools Deep link validator Page") - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.40.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.40.2.md b/src/content/tools/devtools/release-notes/release-notes-2.40.2.md index 5a6b329b6ab..bc49ae547bc 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.40.2.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.40.2.md @@ -1,7 +1,73 @@ --- +title: DevTools 2.40.2 release notes shortTitle: 2.40.2 release notes +breadcrumb: 2.40.2 description: Release notes for Dart and Flutter DevTools version 2.40.2. showToc: false --- -{% include ./release-notes-2.40.2-src.md %} +The 2.40.2 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +* Add a setting that allows users to opt in to loading DevTools + with WebAssembly. - [#8270](https://github.com/flutter/devtools/pull/8270) + + ![Wasm opt-in setting](/assets/images/docs/tools/devtools/release-notes/images-2.40.2/wasm_setting.png "DevTools setting to opt into wasm.") + +* Removed the legacy Provider screen from DevTools. + The `package:provider` tool is now distributed as a + DevTools extension from `package:provider`. + Upgrade your `package:provider` dependency to + use the extension. - [#8364](https://github.com/flutter/devtools/pull/8364) + +* Fixed a bug that was causing the DevTools release notes to + always show. - [#8277](https://github.com/flutter/devtools/pull/8277) + +* Added support for loading extensions in pub workspaces + [8347](https://github.com/flutter/devtools/pull/8347). + +* Mapped error stack traces to use the Dart source code locations so + that they are human-readable. - [#8385](https://github.com/flutter/devtools/pull/8385) + +* Added handling for IDE theme change events to + update embedded DevTools UI. - [#8336](https://github.com/flutter/devtools/pull/8336) + +* Fixed a bug that was causing data filters to be cleared when clearing data + on the Network and Logging screens. - [#8407](https://github.com/flutter/devtools/pull/8407) + +* Fixed a bug that was causing the navigator to lose state when opening the VM + Flags dialog. - [#8413](https://github.com/flutter/devtools/pull/8413) + +* Tables match IDE theme when embedded in an IDE. - [#8498](https://github.com/flutter/devtools/pull/8498) + +## Inspector updates + +- Added a setting to the Flutter Inspector controls that + allows users to opt in to the newly redesigned Flutter Inspector. - [#8342](https://github.com/flutter/devtools/pull/8342) + + ![New inspector opt-in setting](/assets/images/docs/tools/devtools/release-notes/images-2.40.2/new_inspector.png "DevTools setting to opt into the new Flutter Inspector.") + +## Performance updates + +* Fixed an issue with the "Refreshing timeline" overlay that was getting shown + when it should not have been. - [#8318](https://github.com/flutter/devtools/pull/8318) + +## Network profiler updates + +* Resolved an issue in `.har` export where + response content was sometimes missing in the data. - [#8333](https://github.com/flutter/devtools/pull/8333) + +## Deep links tool updates + +- Added support for validating iOS deep link settings. - [#8394](https://github.com/flutter/devtools/pull/8394) + + ![Deep link validator for iOS](/assets/images/docs/tools/devtools/release-notes/images-2.40.2/deep_link_ios.png "DevTools Deep link validator Page") + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.40.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.41.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.41.0-src.md deleted file mode 100644 index c6dcff04c5c..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.41.0-src.md +++ /dev/null @@ -1,62 +0,0 @@ -# DevTools 2.41.0 release notes - -The 2.41.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -* Persist filter settings across sessions. - [#8447](https://github.com/flutter/devtools/pull/8447), -[#8456](https://github.com/flutter/devtools/pull/8456) -[#8470](https://github.com/flutter/devtools/pull/8470) - -## Inspector updates - -* Added an option to the [new Inspector's](https://docs.flutter.dev/tools/devtools/release-notes/release-notes-2.40.2#inspector-updates) - settings to allow auto-refreshing the widget tree after a hot-reload. - [#8483](https://github.com/flutter/devtools/pull/8483) - -## Network profiler updates - -* Added a filter text field to the top-level Network profiler controls. - -[#8469](https://github.com/flutter/devtools/pull/8469) - ![Network filter field](/assets/images/docs/tools/devtools/release-notes/images-2.41.0/network_filter.png "Network filter field") - -## Logging updates - -* Fetch log details immediately upon receiving logs so that log data is not lost -due to lazy loading. - [#8421](https://github.com/flutter/devtools/pull/8421) -* Reduce initial page load time. - [#8500](https://github.com/flutter/devtools/pull/8500) -* Added support for displaying metadata, such as log -severity, category, zone, and isolate - -[#8419](https://github.com/flutter/devtools/pull/8419), -[#8439](https://github.com/flutter/devtools/pull/8439), -[#8441](https://github.com/flutter/devtools/pull/8441). It is now also possible to -search and filter by these metadata values. - [#8473](https://github.com/flutter/devtools/pull/8473) - ![Logging metadata display](/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_metadata.png "Logging metadata display") -* Add a filter text field to the top-level Logging controls. - -[#8427](https://github.com/flutter/devtools/pull/8427) - ![Logging filter](/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_filter.png "Logging filter") -* Added support for filtering by log severity / levels. - -[#8433](https://github.com/flutter/devtools/pull/8433) - ![Log level filter](/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_level_filter.png "Log level filter") -* Added a setting to set the log retention limit. - [#8493](https://github.com/flutter/devtools/pull/8493) -* Added a button to toggle the log details display between raw text and JSON. - -[#8445](https://github.com/flutter/devtools/pull/8445) -* Fixed a bug where logs would get out of order after midnight. - -[#8420](https://github.com/flutter/devtools/pull/8420) -* Automatically scroll logs table to the bottom on the initial load. - -[#8437](https://github.com/flutter/devtools/pull/8437) - -## VS Code Sidebar updates - -* The legacy `postMessage` version of the VS Code sidebar has been removed in -favor of the DTD-powered version. Trying to access the legacy sidebar will -show a message advising to update your Dart VS Code extension. The Dart VS -Code extension was the only user of the legacy sidebar and migrated off in -v3.96. - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.41.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.41.0.md b/src/content/tools/devtools/release-notes/release-notes-2.41.0.md index 5048f0ecf28..0d49629cf55 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.41.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.41.0.md @@ -1,7 +1,68 @@ --- +title: DevTools 2.41.0 release notes shortTitle: 2.41.0 release notes +breadcrumb: 2.41.0 description: Release notes for Dart and Flutter DevTools version 2.41.0. showToc: false --- -{% include ./release-notes-2.41.0-src.md %} +The 2.41.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +* Persist filter settings across sessions. - [#8447](https://github.com/flutter/devtools/pull/8447), + [#8456](https://github.com/flutter/devtools/pull/8456) + [#8470](https://github.com/flutter/devtools/pull/8470) + +## Inspector updates + +* Added an option to the [new Inspector's](https://docs.flutter.dev/tools/devtools/release-notes/release-notes-2.40.2#inspector-updates) + settings to allow auto-refreshing the widget tree after a hot-reload. - [#8483](https://github.com/flutter/devtools/pull/8483) + +## Network profiler updates + +* Added a filter text field to the top-level Network profiler controls. - + [#8469](https://github.com/flutter/devtools/pull/8469) + ![Network filter field](/assets/images/docs/tools/devtools/release-notes/images-2.41.0/network_filter.png "Network filter field") + +## Logging updates + +* Fetch log details immediately upon receiving logs so that log data is not lost + due to lazy loading. - [#8421](https://github.com/flutter/devtools/pull/8421) +* Reduce initial page load time. - [#8500](https://github.com/flutter/devtools/pull/8500) +* Added support for displaying metadata, such as log + severity, category, zone, and isolate - + [#8419](https://github.com/flutter/devtools/pull/8419), + [#8439](https://github.com/flutter/devtools/pull/8439), + [#8441](https://github.com/flutter/devtools/pull/8441). It is now also possible to + search and filter by these metadata values. - [#8473](https://github.com/flutter/devtools/pull/8473) + ![Logging metadata display](/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_metadata.png "Logging metadata display") +* Add a filter text field to the top-level Logging controls. - + [#8427](https://github.com/flutter/devtools/pull/8427) + ![Logging filter](/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_filter.png "Logging filter") +* Added support for filtering by log severity / levels. - + [#8433](https://github.com/flutter/devtools/pull/8433) + ![Log level filter](/assets/images/docs/tools/devtools/release-notes/images-2.41.0/log_level_filter.png "Log level filter") +* Added a setting to set the log retention limit. - [#8493](https://github.com/flutter/devtools/pull/8493) +* Added a button to toggle the log details display between raw text and JSON. - + [#8445](https://github.com/flutter/devtools/pull/8445) +* Fixed a bug where logs would get out of order after midnight. - + [#8420](https://github.com/flutter/devtools/pull/8420) +* Automatically scroll logs table to the bottom on the initial load. - + [#8437](https://github.com/flutter/devtools/pull/8437) + +## VS Code Sidebar updates + +* The legacy `postMessage` version of the VS Code sidebar has been removed in + favor of the DTD-powered version. Trying to access the legacy sidebar will + show a message advising to update your Dart VS Code extension. The Dart VS + Code extension was the only user of the legacy sidebar and migrated off in + v3.96. + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.41.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.42.3-src.md b/src/content/tools/devtools/release-notes/release-notes-2.42.3-src.md deleted file mode 100644 index 28ebb1f20eb..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.42.3-src.md +++ /dev/null @@ -1,30 +0,0 @@ -# DevTools 2.42.3 release notes - -The 2.42.3 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -* Added "View licenses" shortcut to the About dialog. - [#8610](https://github.com/flutter/devtools/pull/8610) - -* Lower the wasm optimization level to resolve crashes on the dart2wasm build. - [#8814](https://github.com/flutter/devtools/pull/8814) - -## Inspector updates - -* Enabled the new inspector by default. This can be disabled in the inspector settings. - [#8650](https://github.com/flutter/devtools/pull/8650) - ![Legacy inspector setting](/assets/images/docs/tools/devtools/release-notes/images-2.42.3/legacy_inspector_setting.png "Legacy inspector setting") -* Fixed an issue where selecting an implementation widget on the device while implementation widgets were hidden in the [new inspector](https://docs.flutter.dev/tools/devtools/release-notes/release-notes-2.40.1#inspector-updates) showed an error. - [#8625](https://github.com/flutter/devtools/pull/8625) -* Enabled auto-refreshes of the widget tree on hot-reloads and navigation events by default. This can be disabled in the inspector settings. - [#8646](https://github.com/flutter/devtools/pull/8646) - ![Auto-refresh setting](/assets/images/docs/tools/devtools/release-notes/images-2.42.3/inspector_auto_refresh_setting.png "Inspector auto-refresh setting") - -## Network profiler updates - -* Fixed an issue where the HTTP requests would sometimes not be displayed properly, particularly when DevTools is communicating -with an application over a slow network connection. - [#8860](https://github.com/flutter/devtools/pull/8860) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.42.3). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.42.3.md b/src/content/tools/devtools/release-notes/release-notes-2.42.3.md index 5fb4132726f..dd65543c5b6 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.42.3.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.42.3.md @@ -1,7 +1,36 @@ --- +title: DevTools 2.42.3 release notes shortTitle: 2.42.3 release notes +breadcrumb: 2.42.3 description: Release notes for Dart and Flutter DevTools version 2.42.3. showToc: false --- -{% include ./release-notes-2.42.3-src.md %} +The 2.42.3 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +* Added "View licenses" shortcut to the About dialog. - [#8610](https://github.com/flutter/devtools/pull/8610) + +* Lower the wasm optimization level to resolve crashes on the dart2wasm build. - [#8814](https://github.com/flutter/devtools/pull/8814) + +## Inspector updates + +* Enabled the new inspector by default. This can be disabled in the inspector settings. - [#8650](https://github.com/flutter/devtools/pull/8650) + ![Legacy inspector setting](/assets/images/docs/tools/devtools/release-notes/images-2.42.3/legacy_inspector_setting.png "Legacy inspector setting") +* Fixed an issue where selecting an implementation widget on the device while implementation widgets were hidden in the [new inspector](https://docs.flutter.dev/tools/devtools/release-notes/release-notes-2.40.1#inspector-updates) showed an error. - [#8625](https://github.com/flutter/devtools/pull/8625) +* Enabled auto-refreshes of the widget tree on hot-reloads and navigation events by default. This can be disabled in the inspector settings. - [#8646](https://github.com/flutter/devtools/pull/8646) + ![Auto-refresh setting](/assets/images/docs/tools/devtools/release-notes/images-2.42.3/inspector_auto_refresh_setting.png "Inspector auto-refresh setting") + +## Network profiler updates + +* Fixed an issue where the HTTP requests would sometimes not be displayed properly, particularly when DevTools is communicating + with an application over a slow network connection. - [#8860](https://github.com/flutter/devtools/pull/8860) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.42.3). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.44.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.44.0-src.md deleted file mode 100644 index 7fc0d06dcd5..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.44.0-src.md +++ /dev/null @@ -1,68 +0,0 @@ -# DevTools 2.44.0 release notes - -The 2.44.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -* Fixed various memory leaks and lifecycle issues. - -[#8901](https://github.com/flutter/devtools/pull/8901), -[#8902](https://github.com/flutter/devtools/pull/8902), -[#8907](https://github.com/flutter/devtools/pull/8907), -[#8917](https://github.com/flutter/devtools/pull/8917), -[#8932](https://github.com/flutter/devtools/pull/8932), -[#8933](https://github.com/flutter/devtools/pull/8933), -[#8934](https://github.com/flutter/devtools/pull/8934), -[#8935](https://github.com/flutter/devtools/pull/8935), -[#8937](https://github.com/flutter/devtools/pull/8937), -[#8953](https://github.com/flutter/devtools/pull/8953), -[#8969](https://github.com/flutter/devtools/pull/8969), -[#8970](https://github.com/flutter/devtools/pull/8970), -[#8975](https://github.com/flutter/devtools/pull/8975) - -## CPU profiler updates - -* Improved the load time and memory usage of CPU profiles. - * [#8892](https://github.com/flutter/devtools/pull/8892) - * [#8878](https://github.com/flutter/devtools/pull/8878) - * [#8839](https://github.com/flutter/devtools/pull/8839) -* Fixed incorrect duration calculations when there is time during which no - samples were taken - [#8941](https://github.com/flutter/devtools/pull/8941). - -## Memory updates - -* Changed the memory heap snapshot tool so that references are - included in snapshots by default. - - [#8899](https://github.com/flutter/devtools/pull/8899) - -## Debugger updates - -* Added a tooltip to describe the exception mode drop-down. - - [#8849](https://github.com/flutter/devtools/pull/8849) -* Updated syntax highlighting with support for digit separators - and improved comment and string interpolation handling. - - [#8861](https://github.com/flutter/devtools/pull/8861) -* Updated `string_scanner` dependency to avoid some syntax highlighting issues - when source contains `\r\n` in certain positions on Windows. - - [#8904](https://github.com/flutter/devtools/pull/8904) -* Added soft line wrapping in the debugger console. - [#8855](https://github.com/flutter/devtools/pull/8855). - -## Network profiler updates - -* Added offline support for the network screen (thanks to @hrajwade96!) - - [#8332](https://github.com/flutter/devtools/pull/8332) - - ![Network profiler controls](/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_controls.png "Network profiler controls") - - ![Network profiler open / save button](/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_open_save_button.png "Network profiler open / save button") - -* Changed the context menu style to be consistent with other screens - [#8859](https://github.com/flutter/devtools/pull/8859). - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.44.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.44.0.md b/src/content/tools/devtools/release-notes/release-notes-2.44.0.md index cefb04f6054..aec52c70975 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.44.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.44.0.md @@ -1,7 +1,74 @@ --- +title: DevTools 2.44.0 release notes shortTitle: 2.44.0 release notes +breadcrumb: 2.44.0 description: Release notes for Dart and Flutter DevTools version 2.44.0. showToc: false --- -{% include ./release-notes-2.44.0-src.md %} +The 2.44.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +* Fixed various memory leaks and lifecycle issues. - + [#8901](https://github.com/flutter/devtools/pull/8901), + [#8902](https://github.com/flutter/devtools/pull/8902), + [#8907](https://github.com/flutter/devtools/pull/8907), + [#8917](https://github.com/flutter/devtools/pull/8917), + [#8932](https://github.com/flutter/devtools/pull/8932), + [#8933](https://github.com/flutter/devtools/pull/8933), + [#8934](https://github.com/flutter/devtools/pull/8934), + [#8935](https://github.com/flutter/devtools/pull/8935), + [#8937](https://github.com/flutter/devtools/pull/8937), + [#8953](https://github.com/flutter/devtools/pull/8953), + [#8969](https://github.com/flutter/devtools/pull/8969), + [#8970](https://github.com/flutter/devtools/pull/8970), + [#8975](https://github.com/flutter/devtools/pull/8975) + +## CPU profiler updates + +* Improved the load time and memory usage of CPU profiles. + * [#8892](https://github.com/flutter/devtools/pull/8892) + * [#8878](https://github.com/flutter/devtools/pull/8878) + * [#8839](https://github.com/flutter/devtools/pull/8839) +* Fixed incorrect duration calculations when there is time during which no + samples were taken - [#8941](https://github.com/flutter/devtools/pull/8941). + +## Memory updates + +* Changed the memory heap snapshot tool so that references are + included in snapshots by default. - + [#8899](https://github.com/flutter/devtools/pull/8899) + +## Debugger updates + +* Added a tooltip to describe the exception mode drop-down. - + [#8849](https://github.com/flutter/devtools/pull/8849) +* Updated syntax highlighting with support for digit separators + and improved comment and string interpolation handling. - + [#8861](https://github.com/flutter/devtools/pull/8861) +* Updated `string_scanner` dependency to avoid some syntax highlighting issues + when source contains `\r\n` in certain positions on Windows. - + [#8904](https://github.com/flutter/devtools/pull/8904) +* Added soft line wrapping in the debugger console. + [#8855](https://github.com/flutter/devtools/pull/8855). + +## Network profiler updates + +* Added offline support for the network screen (thanks to @hrajwade96!) - + [#8332](https://github.com/flutter/devtools/pull/8332) + + ![Network profiler controls](/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_controls.png "Network profiler controls") + + ![Network profiler open / save button](/assets/images/docs/tools/devtools/release-notes/images-2.44.0/network_open_save_button.png "Network profiler open / save button") + +* Changed the context menu style to be consistent with other screens + [#8859](https://github.com/flutter/devtools/pull/8859). + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.44.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.45.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.45.0-src.md deleted file mode 100644 index 0eb6b8087f2..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.45.0-src.md +++ /dev/null @@ -1,48 +0,0 @@ -# DevTools 2.45.0 release notes - -The 2.45.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -* Added a memory pressure warning that allows you to reduce the memory usage of -DevTools in order to avoid an OOM crash. - -[#8989](https://github.com/flutter/devtools/pull/8989), -[#8997](https://github.com/flutter/devtools/pull/8997), -[#8998](https://github.com/flutter/devtools/pull/8998) - -* Fix a bug with the review history on disconnect experience. - -[#8985](https://github.com/flutter/devtools/pull/8985) - -* Fixed bug where DevTools would automatically resume instead of -pausing on breakpoint on connection. - -[#8991](https://github.com/flutter/devtools/pull/8991) - -* Prevented text inputs from stealing focus from the IDE. - -[#9091](https://github.com/flutter/devtools/pull/9091) - -## Inspector updates - -* Fixed bug where errors in the inspector tree (e.g. RenderFlex overflow -errors) were not removed after a hot-reload. - -[#9106](https://github.com/flutter/devtools/pull/9106) - -## Debugger updates - -* Combine the Pause and Resume buttons into a single button. - -[#9095](https://github.com/flutter/devtools/pull/9095) - -## Deep links tool updates - -* Fixed an issue with Windows file paths showing incorrectly in the Deep Links -page [#9027](https://github.com/flutter/devtools/pull/9027). - -* Fixed an issue with the Deep Links page crashing when no iOS configuration is -present [#9027](https://github.com/flutter/devtools/pull/9027). - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.45.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.45.0.md b/src/content/tools/devtools/release-notes/release-notes-2.45.0.md index a2215e774f6..91780679217 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.45.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.45.0.md @@ -1,7 +1,54 @@ --- +title: DevTools 2.45.0 release notes shortTitle: 2.45.0 release notes +breadcrumb: 2.45.0 description: Release notes for Dart and Flutter DevTools version 2.45.0. showToc: false --- -{% include ./release-notes-2.45.0-src.md %} +The 2.45.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +* Added a memory pressure warning that allows you to reduce the memory usage of + DevTools in order to avoid an OOM crash. - + [#8989](https://github.com/flutter/devtools/pull/8989), + [#8997](https://github.com/flutter/devtools/pull/8997), + [#8998](https://github.com/flutter/devtools/pull/8998) + +* Fix a bug with the review history on disconnect experience. - + [#8985](https://github.com/flutter/devtools/pull/8985) + +* Fixed bug where DevTools would automatically resume instead of + pausing on breakpoint on connection. - + [#8991](https://github.com/flutter/devtools/pull/8991) + +* Prevented text inputs from stealing focus from the IDE. - + [#9091](https://github.com/flutter/devtools/pull/9091) + +## Inspector updates + +* Fixed bug where errors in the inspector tree (e.g. RenderFlex overflow + errors) were not removed after a hot-reload. - + [#9106](https://github.com/flutter/devtools/pull/9106) + +## Debugger updates + +* Combine the Pause and Resume buttons into a single button. - + [#9095](https://github.com/flutter/devtools/pull/9095) + +## Deep links tool updates + +* Fixed an issue with Windows file paths showing incorrectly in the Deep Links + page [#9027](https://github.com/flutter/devtools/pull/9027). + +* Fixed an issue with the Deep Links page crashing when no iOS configuration is + present [#9027](https://github.com/flutter/devtools/pull/9027). + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.45.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.46.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.46.0-src.md deleted file mode 100644 index 62e01087c0c..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.46.0-src.md +++ /dev/null @@ -1,23 +0,0 @@ -# DevTools 2.46.0 release notes - -The 2.46.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -- Fixed a bug which caused web apps to remain paused after triggering a hot-restart from -DevTools. - [#9125](https://github.com/flutter/devtools/pull/9125) -- Landed a change to dismiss stale banner messages when the connected app state changes. - [#9148](https://github.com/flutter/devtools/pull/9148) -- Fixed a focus traversal issue with search fields. [#9166](https://github.com/flutter/devtools/pull/9166) - -## Performance updates - -- Fixed a bug where the Performance page would hang when connected to a paused -Flutter app. - [#9162](https://github.com/flutter/devtools/pull/9162) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.46.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.46.0.md b/src/content/tools/devtools/release-notes/release-notes-2.46.0.md index 49e8b64ad09..f9d76f39ee8 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.46.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.46.0.md @@ -1,7 +1,29 @@ --- +title: DevTools 2.46.0 release notes shortTitle: 2.46.0 release notes +breadcrumb: 2.46.0 description: Release notes for Dart and Flutter DevTools version 2.46.0. showToc: false --- -{% include ./release-notes-2.46.0-src.md %} +The 2.46.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +- Fixed a bug which caused web apps to remain paused after triggering a hot-restart from + DevTools. - [#9125](https://github.com/flutter/devtools/pull/9125) +- Landed a change to dismiss stale banner messages when the connected app state changes. - [#9148](https://github.com/flutter/devtools/pull/9148) +- Fixed a focus traversal issue with search fields. [#9166](https://github.com/flutter/devtools/pull/9166) + +## Performance updates + +- Fixed a bug where the Performance page would hang when connected to a paused + Flutter app. - [#9162](https://github.com/flutter/devtools/pull/9162) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.46.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.47.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.47.0-src.md deleted file mode 100644 index ca1b912b375..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.47.0-src.md +++ /dev/null @@ -1,16 +0,0 @@ -# DevTools 2.47.0 release notes - -The 2.47.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -- Fixed an issue where copying all logs in the console would show `null` for -any inspected widgets. - [#9204](https://github.com/flutter/devtools/pull/9204) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.47.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.47.0.md b/src/content/tools/devtools/release-notes/release-notes-2.47.0.md index 40f447594e9..b231efa6a18 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.47.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.47.0.md @@ -1,7 +1,22 @@ --- +title: DevTools 2.47.0 release notes shortTitle: 2.47.0 release notes +breadcrumb: 2.47.0 description: Release notes for Dart and Flutter DevTools version 2.47.0. showToc: false --- -{% include ./release-notes-2.47.0-src.md %} +The 2.47.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +- Fixed an issue where copying all logs in the console would show `null` for + any inspected widgets. - [#9204](https://github.com/flutter/devtools/pull/9204) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.47.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.48.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.48.0-src.md deleted file mode 100644 index 68510f95023..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.48.0-src.md +++ /dev/null @@ -1,29 +0,0 @@ -# DevTools 2.48.0 release notes - -The 2.48.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## Network profiler updates - -* Fixed network logging after a hot restart. - - [#9271](https://github.com/flutter/devtools/pull/9271). - -## Logging updates - -* Started displaying events related to timers in the Logging View. - - [#9238](https://github.com/flutter/devtools/pull/9238). - -## Advanced developer mode updates - -* Added a Queued Microtasks tab to the VM Tools screen, which allows a user to - see details about the microtasks scheduled in an isolate's microtask queue. - This tab currently only appears when DevTools is connected to a Flutter or - Dart app started with `--profile-microtasks`. - - [#9239](https://github.com/flutter/devtools/pull/9239). - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.48.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.48.0.md b/src/content/tools/devtools/release-notes/release-notes-2.48.0.md index 9bf791d0e5e..e443e8ec575 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.48.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.48.0.md @@ -1,7 +1,35 @@ --- +title: DevTools 2.48.0 release notes shortTitle: 2.48.0 release notes +breadcrumb: 2.48.0 description: Release notes for Dart and Flutter DevTools version 2.48.0. showToc: false --- -{% include ./release-notes-2.48.0-src.md %} +The 2.48.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## Network profiler updates + +* Fixed network logging after a hot restart. - + [#9271](https://github.com/flutter/devtools/pull/9271). + +## Logging updates + +* Started displaying events related to timers in the Logging View. - + [#9238](https://github.com/flutter/devtools/pull/9238). + +## Advanced developer mode updates + +* Added a Queued Microtasks tab to the VM Tools screen, which allows a user to + see details about the microtasks scheduled in an isolate's microtask queue. + This tab currently only appears when DevTools is connected to a Flutter or + Dart app started with `--profile-microtasks`. - + [#9239](https://github.com/flutter/devtools/pull/9239). + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.48.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.49.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.49.0-src.md deleted file mode 100644 index c56ff24a0a8..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.49.0-src.md +++ /dev/null @@ -1,17 +0,0 @@ -# DevTools 2.49.0 release notes - -The 2.49.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -- Fixed a bug preventing the buttons at the top of an embedded DevTools screen - from being clicked under certain circumstances. - - [#9327](https://github.com/flutter/devtools/pull/9327) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.49.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.49.0.md b/src/content/tools/devtools/release-notes/release-notes-2.49.0.md index f845fe25d95..61c6925f07c 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.49.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.49.0.md @@ -1,7 +1,23 @@ --- +title: DevTools 2.49.0 release notes shortTitle: 2.49.0 release notes +breadcrumb: 2.49.0 description: Release notes for Dart and Flutter DevTools version 2.49.0. showToc: false --- -{% include ./release-notes-2.49.0-src.md %} +The 2.49.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +- Fixed a bug preventing the buttons at the top of an embedded DevTools screen + from being clicked under certain circumstances. - + [#9327](https://github.com/flutter/devtools/pull/9327) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.49.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.50.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.50.0-src.md deleted file mode 100644 index d530bf3342d..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.50.0-src.md +++ /dev/null @@ -1,17 +0,0 @@ -# DevTools 2.50.0 release notes - -The 2.50.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## CPU profiler updates - -- Deleted the "Profile app start up" button in favor of the new Dart/Flutter - `--profile-startup` CLI flags. - - [#9358](https://github.com/flutter/devtools/pull/9358) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.50.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.50.0.md b/src/content/tools/devtools/release-notes/release-notes-2.50.0.md index 70c37f533a5..bca6780424a 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.50.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.50.0.md @@ -1,7 +1,23 @@ --- +title: DevTools 2.50.0 release notes shortTitle: 2.50.0 release notes +breadcrumb: 2.50.0 description: Release notes for Dart and Flutter DevTools version 2.50.0. showToc: false --- -{% include ./release-notes-2.50.0-src.md %} +The 2.50.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## CPU profiler updates + +- Deleted the "Profile app start up" button in favor of the new Dart/Flutter + `--profile-startup` CLI flags. - + [#9358](https://github.com/flutter/devtools/pull/9358) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.50.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.51.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.51.0-src.md deleted file mode 100644 index 2124e505900..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.51.0-src.md +++ /dev/null @@ -1,23 +0,0 @@ -# DevTools 2.51.0 release notes - -The 2.51.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools/overview). - -## General updates - -- Flutter beta channel users were opted into the DevTools-on-Wasm experiment. - All other users can still enable the Wasm-compiled DevTools from the settings - dialog. - [#9455](https://github.com/flutter/devtools/pull/9455) - -## Inspector updates - -- Fixed an issue where selecting a widget with the Inspector would open the - widget definition file instead of the user's project file. - - [#176530](https://github.com/flutter/flutter/pull/176530) - -## Full commit history - -To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.51.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.51.0.md b/src/content/tools/devtools/release-notes/release-notes-2.51.0.md index 54c98545714..b2d3fe6d98f 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.51.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.51.0.md @@ -1,7 +1,29 @@ --- -short-title: 2.51.0 release notes +title: DevTools 2.51.0 release notes +shortTitle: 2.51.0 release notes +breadcrumb: 2.51.0 description: Release notes for Dart and Flutter DevTools version 2.51.0. -toc: false +showToc: false --- -{% include ./release-notes-2.51.0-src.md %} +The 2.51.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools/overview). + +## General updates + +- Flutter beta channel users were opted into the DevTools-on-Wasm experiment. + All other users can still enable the Wasm-compiled DevTools from the settings + dialog. - [#9455](https://github.com/flutter/devtools/pull/9455) + +## Inspector updates + +- Fixed an issue where selecting a widget with the Inspector would open the + widget definition file instead of the user's project file. - + [#176530](https://github.com/flutter/flutter/pull/176530) + +## Full commit history + +To find a complete list of changes in this release, check out the +[DevTools git log](https://github.com/flutter/devtools/tree/v2.51.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.7.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.7.0-src.md deleted file mode 100644 index 0cb18ae5f96..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.7.0-src.md +++ /dev/null @@ -1,64 +0,0 @@ -# DevTools 2.7.0 release notes - -The 2.7.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](/tools/devtools). - -## General updates - -* Improvements for initial page load time - - [#3309](https://github.com/flutter/devtools/pull/3309) -* Fix a couple scrollbar-related issues - - [#3393](https://github.com/flutter/devtools/pull/3393), - [#3401](https://github.com/flutter/devtools/pull/3401) - -## Debugger updates - -* Add an open file dialog (ctrl / cmd + p) - - [#3342](https://github.com/flutter/devtools/pull/3342), - [#3354](https://github.com/flutter/devtools/pull/3354), - [#3371](https://github.com/flutter/devtools/pull/3371), - [#3384](https://github.com/flutter/devtools/pull/3384) - - ![Open file dialog](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image1.gif "Open file dialog") - -* Add a copy button to the call stack view - - [#3334](https://github.com/flutter/devtools/pull/3334) - - ![Call stack view](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image2.png "Call stack view") - -## CPU profiler updates - -* Added functionality to load an app startup profile for Flutter apps. - This profile will contain CPU samples from the initialization - of the Dart VM up until the first Flutter frame has been rendered - - [#3357](https://github.com/flutter/devtools/pull/3357) - - ![Profile button](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image3.png "Profile button") - - When the app startup profile has been loaded, - you will see that the "AppStartUp" user tag is selected for the profile. - You can also load the app startup profile - by selecting this user tag filter, when present, - in the list of available user tags. - - ![User tag example](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image4.png "User tag example") - -* Added multi-isolate support. - Select which isolate you want to profile - from the isolate selector at the bottom of the page - - [#3362](https://github.com/flutter/devtools/pull/3362) - - ![isolate selector](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image5.png "isolate selector") - -* Add class names to CPU stack frames in the profiler - - [#3385](https://github.com/flutter/devtools/pull/3385) - - ![Class names](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image6.png "Class names") - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.6.0...v2.7.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.7.0.md b/src/content/tools/devtools/release-notes/release-notes-2.7.0.md index 9d608943f2e..f66d1f9d41e 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.7.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.7.0.md @@ -1,7 +1,70 @@ --- +title: DevTools 2.7.0 release notes shortTitle: 2.7.0 release notes +breadcrumb: 2.7.0 description: Release notes for Dart and Flutter DevTools version 2.7.0. showToc: false --- -{% include ./release-notes-2.7.0-src.md %} +The 2.7.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](/tools/devtools). + +## General updates + +* Improvements for initial page load time - + [#3309](https://github.com/flutter/devtools/pull/3309) +* Fix a couple scrollbar-related issues - + [#3393](https://github.com/flutter/devtools/pull/3393), + [#3401](https://github.com/flutter/devtools/pull/3401) + +## Debugger updates + +* Add an open file dialog (ctrl / cmd + p) - + [#3342](https://github.com/flutter/devtools/pull/3342), + [#3354](https://github.com/flutter/devtools/pull/3354), + [#3371](https://github.com/flutter/devtools/pull/3371), + [#3384](https://github.com/flutter/devtools/pull/3384) + + ![Open file dialog](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image1.gif "Open file dialog") + +* Add a copy button to the call stack view - + [#3334](https://github.com/flutter/devtools/pull/3334) + + ![Call stack view](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image2.png "Call stack view") + +## CPU profiler updates + +* Added functionality to load an app startup profile for Flutter apps. + This profile will contain CPU samples from the initialization + of the Dart VM up until the first Flutter frame has been rendered - + [#3357](https://github.com/flutter/devtools/pull/3357) + + ![Profile button](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image3.png "Profile button") + + When the app startup profile has been loaded, + you will see that the "AppStartUp" user tag is selected for the profile. + You can also load the app startup profile + by selecting this user tag filter, when present, + in the list of available user tags. + + ![User tag example](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image4.png "User tag example") + +* Added multi-isolate support. + Select which isolate you want to profile + from the isolate selector at the bottom of the page - + [#3362](https://github.com/flutter/devtools/pull/3362) + + ![isolate selector](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image5.png "isolate selector") + +* Add class names to CPU stack frames in the profiler - + [#3385](https://github.com/flutter/devtools/pull/3385) + + ![Class names](/assets/images/docs/tools/devtools/release-notes/images-2.7.0/image6.png "Class names") + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.6.0...v2.7.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.8.0-src.md b/src/content/tools/devtools/release-notes/release-notes-2.8.0-src.md deleted file mode 100644 index 71d3eecb3d1..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.8.0-src.md +++ /dev/null @@ -1,93 +0,0 @@ -# DevTools 2.8.0 release notes - -The 2.8.0 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Improvements for initial page load time - - [#3325](https://github.com/flutter/devtools/pull/3325) -* Performance improvements for connecting DevTools to a device, - particularly impactful for low-memory devices - - [#3468](https://github.com/flutter/devtools/pull/3468) -* For users on Flutter 2.8.0 or greater (or Dart 2.15.0 or greater), - DevTools should now be launched via the `dart devtools` command - instead of running `pub global activate devtools`. - DevTools 2.8.0 will be the last version of DevTools shipped on pub, - and all future versions of DevTools will be shipped as part of the Dart SDK. - If you see this warning, - be sure to open DevTools via `dart devtools` instead of from pub: - - ![dart devtools warning dialog](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image1.png "dart devtools warning dialog") - -## Performance updates - -* Added a new "Enhance Tracing" feature to help users diagnose UI jank - stemming from expensive Build, Layout, and Paint operations. - - ![Enhance tracing](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image2.png "Enhance tracing") - - The expected workflow is as such: - - 1. User is investigating UI jank in the performance page - 2. User notices a long Build, Layout, and/or Paint event - 3. User turns on the respective tracking toggle in the "Enhance Tracing" feature - 4. User reproduces the UI jank in their app - 5. User looks at the new set of Timeline events, which should now have - additional child events for widgets built, render objects laid out, - and/or render objects painted - - ![Timeline events](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image3.png "Timeline events") - -* Added new "More debugging options" feature to allow for disabling - rendering layers for Clip, Opacity, and Physical Shapes. - - ![More debugging options](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image4.png "More debugging options") - - The expected workflow is as such: - - 1. User is investigating UI jank in the performance page - 2. User notices a lot of janky frames and suspects it could be due to - excessive use of clipping, opacity, or physical shapes. - 3. User turns off the respective render layer toggle in the "More - debugging options" feature - 4. User reproduces the UI jank in their app - 5. If the UI jank is reduced with a rendering layer turned off, - the user should try to optimize their app to use - less clipping/opacity/physical shape effects. - If the UI jank is not reduced, - the user now knows that the performance problem - is not due to these UI effects. - -## Debugger updates - -* Replaced the "Libraries" pane with a "File Explorer" pane - - [#3448](https://github.com/flutter/devtools/pull/3448). - The "File Explorer" pane has two components: - - 1. A tree view of the libraries present in your application. - You can use the File Explorer to find and open a library, - or you can use the existing Ctrl / Cmd + - P keyboard shortcut to search for a file. - 1. A new "Outline" view that shows the structure of the selected library. - This view will show classes, members, methods, etc., - and when an item is selected, - the source view will jump to the respective line of code - for the selected item. - - ![Outline view selected library](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image5.png "Outline view selected library") - -* Performance improvements to expression evaluation auto complete - - [#3463](https://github.com/flutter/devtools/pull/3463) -* Fixed a bug with keyboard shortcuts - - [#3458](https://github.com/flutter/devtools/pull/3458) -* UI polish - [#3421](https://github.com/flutter/devtools/pull/3421), - [#3449](https://github.com/flutter/devtools/pull/3449) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.7.0...v2.8.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.8.0.md b/src/content/tools/devtools/release-notes/release-notes-2.8.0.md index f87f97a5790..605759db9fa 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.8.0.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.8.0.md @@ -1,7 +1,99 @@ --- +title: DevTools 2.8.0 release notes shortTitle: 2.8.0 release notes +breadcrumb: 2.8.0 description: Release notes for Dart and Flutter DevTools version 2.8.0. showToc: false --- -{% include ./release-notes-2.8.0-src.md %} +The 2.8.0 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Improvements for initial page load time - + [#3325](https://github.com/flutter/devtools/pull/3325) +* Performance improvements for connecting DevTools to a device, + particularly impactful for low-memory devices - + [#3468](https://github.com/flutter/devtools/pull/3468) +* For users on Flutter 2.8.0 or greater (or Dart 2.15.0 or greater), + DevTools should now be launched via the `dart devtools` command + instead of running `pub global activate devtools`. + DevTools 2.8.0 will be the last version of DevTools shipped on pub, + and all future versions of DevTools will be shipped as part of the Dart SDK. + If you see this warning, + be sure to open DevTools via `dart devtools` instead of from pub: + + ![dart devtools warning dialog](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image1.png "dart devtools warning dialog") + +## Performance updates + +* Added a new "Enhance Tracing" feature to help users diagnose UI jank + stemming from expensive Build, Layout, and Paint operations. + + ![Enhance tracing](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image2.png "Enhance tracing") + + The expected workflow is as such: + + 1. User is investigating UI jank in the performance page + 2. User notices a long Build, Layout, and/or Paint event + 3. User turns on the respective tracking toggle in the "Enhance Tracing" feature + 4. User reproduces the UI jank in their app + 5. User looks at the new set of Timeline events, which should now have + additional child events for widgets built, render objects laid out, + and/or render objects painted + + ![Timeline events](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image3.png "Timeline events") + +* Added new "More debugging options" feature to allow for disabling + rendering layers for Clip, Opacity, and Physical Shapes. + + ![More debugging options](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image4.png "More debugging options") + + The expected workflow is as such: + + 1. User is investigating UI jank in the performance page + 2. User notices a lot of janky frames and suspects it could be due to + excessive use of clipping, opacity, or physical shapes. + 3. User turns off the respective render layer toggle in the "More + debugging options" feature + 4. User reproduces the UI jank in their app + 5. If the UI jank is reduced with a rendering layer turned off, + the user should try to optimize their app to use + less clipping/opacity/physical shape effects. + If the UI jank is not reduced, + the user now knows that the performance problem + is not due to these UI effects. + +## Debugger updates + +* Replaced the "Libraries" pane with a "File Explorer" pane - + [#3448](https://github.com/flutter/devtools/pull/3448). + The "File Explorer" pane has two components: + + 1. A tree view of the libraries present in your application. + You can use the File Explorer to find and open a library, + or you can use the existing Ctrl / Cmd + + P keyboard shortcut to search for a file. + 1. A new "Outline" view that shows the structure of the selected library. + This view will show classes, members, methods, etc., + and when an item is selected, + the source view will jump to the respective line of code + for the selected item. + + ![Outline view selected library](/assets/images/docs/tools/devtools/release-notes/images-2.8.0/image5.png "Outline view selected library") + +* Performance improvements to expression evaluation auto complete - + [#3463](https://github.com/flutter/devtools/pull/3463) +* Fixed a bug with keyboard shortcuts - + [#3458](https://github.com/flutter/devtools/pull/3458) +* UI polish - [#3421](https://github.com/flutter/devtools/pull/3421), + [#3449](https://github.com/flutter/devtools/pull/3449) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.7.0...v2.8.0). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.9.1-src.md b/src/content/tools/devtools/release-notes/release-notes-2.9.1-src.md deleted file mode 100644 index 7250e9be286..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.9.1-src.md +++ /dev/null @@ -1,35 +0,0 @@ -# DevTools 2.9.1 release notes - -The 2.9.1 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## Debugger updates - -* Improve support for inspecting large lists and maps in - the Debugger variables pane - [#3497](https://github.com/flutter/devtools/pull/3497) - - ![Inspection before](/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image1.png "Inspection before") - - ![Inspection after](/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image2.png "Inspection after") - -* Added support for selecting objects in the program explorer outline view. - Selecting an object will automatically scroll the source code - in the debugger to the selected object - - [#3480](https://github.com/flutter/devtools/pull/3480) - -## Performance updates - -* Fix bugs with performance page search and improve performance - - [#3515](https://github.com/flutter/devtools/pull/3515) -* Added an enhanced tooltip for flutter frames - - [#3493](https://github.com/flutter/devtools/pull/3493) - - ![Flutter frame tooltips](/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image3.png "Flutter frame tooltips") - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.8.0...v2.9.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.9.1.md b/src/content/tools/devtools/release-notes/release-notes-2.9.1.md index d1114c75e11..bb6474c9913 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.9.1.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.9.1.md @@ -1,7 +1,41 @@ --- +title: DevTools 2.9.1 release notes shortTitle: 2.9.1 release notes +breadcrumb: 2.9.1 description: Release notes for Dart and Flutter DevTools version 2.9.1. showToc: false --- -{% include ./release-notes-2.9.1-src.md %} +The 2.9.1 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## Debugger updates + +* Improve support for inspecting large lists and maps in + the Debugger variables pane - [#3497](https://github.com/flutter/devtools/pull/3497) + + ![Inspection before](/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image1.png "Inspection before") + + ![Inspection after](/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image2.png "Inspection after") + +* Added support for selecting objects in the program explorer outline view. + Selecting an object will automatically scroll the source code + in the debugger to the selected object - + [#3480](https://github.com/flutter/devtools/pull/3480) + +## Performance updates + +* Fix bugs with performance page search and improve performance - + [#3515](https://github.com/flutter/devtools/pull/3515) +* Added an enhanced tooltip for flutter frames - + [#3493](https://github.com/flutter/devtools/pull/3493) + + ![Flutter frame tooltips](/assets/images/docs/tools/devtools/release-notes/images-2.9.1/image3.png "Flutter frame tooltips") + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.8.0...v2.9.1). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.9.2-src.md b/src/content/tools/devtools/release-notes/release-notes-2.9.2-src.md deleted file mode 100644 index 03b21ccd809..00000000000 --- a/src/content/tools/devtools/release-notes/release-notes-2.9.2-src.md +++ /dev/null @@ -1,46 +0,0 @@ -# DevTools 2.9.2 release notes - -The 2.9.2 release of the Dart and Flutter DevTools -includes the following changes among other general improvements. -To learn more about DevTools, check out the -[DevTools overview](https://docs.flutter.dev/tools/devtools). - -## General updates - -* Take our 2022 DevTools survey! Provide your feedback and help us improve - your development experience. This survey prompt will show up directly in - DevTools sometime in mid-February. - - ![survey prompt](/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image1.png "survey_prompt") - - *Note*: If you are having issues launching the survey, please make - sure you have upgraded to the latest Flutter stable branch 2.10. - There was a bug in DevTools (fixed in - [#3574](https://github.com/flutter/devtools/pull/3574)) that - prevented the survey from being able to be opened, and unless you - are on Flutter 2.10, this bug will still be present._ - -* General bug fixes and improvements - - [#3528](https://github.com/flutter/devtools/pull/3528), - [#3531](https://github.com/flutter/devtools/pull/3531), - [#3532](https://github.com/flutter/devtools/pull/3532), - [#3539](https://github.com/flutter/devtools/pull/3539) - -## Performance updates - -* Added frame numbers to x-axis the Flutter frames chart - - [#3526](https://github.com/flutter/devtools/pull/3526) - - ![frame numbers](/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image2.png "frame_numbers") - -## Debugger updates - -* Fix a bug where the File Explorer in the Debugger did not show contents - after a hot restart - - [#3527](https://github.com/flutter/devtools/pull/3527) - -## Full commit history - -To find a complete list of changes since the previous release, -check out -[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.9.1...v2.9.2). diff --git a/src/content/tools/devtools/release-notes/release-notes-2.9.2.md b/src/content/tools/devtools/release-notes/release-notes-2.9.2.md index 1e6d26645ae..4e1ccb55977 100644 --- a/src/content/tools/devtools/release-notes/release-notes-2.9.2.md +++ b/src/content/tools/devtools/release-notes/release-notes-2.9.2.md @@ -1,7 +1,52 @@ --- +title: DevTools 2.9.2 release notes shortTitle: 2.9.2 release notes +breadcrumb: 2.9.2 description: Release notes for Dart and Flutter DevTools version 2.9.2. showToc: false --- -{% include ./release-notes-2.9.2-src.md %} +The 2.9.2 release of the Dart and Flutter DevTools +includes the following changes among other general improvements. +To learn more about DevTools, check out the +[DevTools overview](https://docs.flutter.dev/tools/devtools). + +## General updates + +* Take our 2022 DevTools survey! Provide your feedback and help us improve + your development experience. This survey prompt will show up directly in + DevTools sometime in mid-February. + + ![survey prompt](/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image1.png "survey_prompt") + + *Note*: If you are having issues launching the survey, please make + sure you have upgraded to the latest Flutter stable branch 2.10. + There was a bug in DevTools (fixed in + [#3574](https://github.com/flutter/devtools/pull/3574)) that + prevented the survey from being able to be opened, and unless you + are on Flutter 2.10, this bug will still be present._ + +* General bug fixes and improvements - + [#3528](https://github.com/flutter/devtools/pull/3528), + [#3531](https://github.com/flutter/devtools/pull/3531), + [#3532](https://github.com/flutter/devtools/pull/3532), + [#3539](https://github.com/flutter/devtools/pull/3539) + +## Performance updates + +* Added frame numbers to x-axis the Flutter frames chart - + [#3526](https://github.com/flutter/devtools/pull/3526) + + ![frame numbers](/assets/images/docs/tools/devtools/release-notes/images-2.9.2/image2.png "frame_numbers") + +## Debugger updates + +* Fix a bug where the File Explorer in the Debugger did not show contents + after a hot restart - + [#3527](https://github.com/flutter/devtools/pull/3527) + +## Full commit history + +To find a complete list of changes since the previous release, +check out +[the diff on GitHub](https://github.com/flutter/devtools/compare/v2.9.1...v2.9.2). diff --git a/src/content/tools/devtools/release-notes/releases.liquid b/src/content/tools/devtools/release-notes/releases.liquid deleted file mode 100644 index 174b5dd225c..00000000000 --- a/src/content/tools/devtools/release-notes/releases.liquid +++ /dev/null @@ -1,15 +0,0 @@ ---- -permalink: /f/devtools-releases.json -layout: none ---- - -{%- assign releases = devtools_releases.releases -%} -{%- assign latest = releases | first -%} -{ - "latest": "{{latest}}", - "releases": { - {%- for release in releases %} - "{{release}}": "/tools/devtools/release-notes/release-notes-{{release}}-src.md"{%- unless forloop.last -%},{%- endunless -%} - {%- endfor %} - } -} diff --git a/src/content/tutorial/index.md b/src/content/tutorial/index.md index 659fee3218a..17d47b0ffee 100644 --- a/src/content/tutorial/index.md +++ b/src/content/tutorial/index.md @@ -2,6 +2,7 @@ title: Learn Flutter description: Resources to help you learn Flutter. showToc: false +sitemap: false --- ## Welcome! diff --git a/src/content/tutorial/state/1-set-up-project.md b/src/content/tutorial/state/1-set-up-project.md index 698cb609eb7..a44927e437b 100644 --- a/src/content/tutorial/state/1-set-up-project.md +++ b/src/content/tutorial/state/1-set-up-project.md @@ -2,6 +2,7 @@ title: Set up your project description: Instructions on how to create a new Flutter app. permalink: /tutorial/set-up-state-app/ +sitemap: false --- In this tutorial, you'll learn how to work with data in a Flutter app. diff --git a/src/content/tutorial/state/2-http-requests.md b/src/content/tutorial/state/2-http-requests.md index 8f41ab6a7c0..7085cc4dd25 100644 --- a/src/content/tutorial/state/2-http-requests.md +++ b/src/content/tutorial/state/2-http-requests.md @@ -2,6 +2,7 @@ title: Fetch data from the internet description: Instructions on how to make HTTP requests and parse responses. permalink: /tutorial/http-request/ +sitemap: false --- The overarching pattern that this tutorial implements is called diff --git a/src/content/tutorial/state/3-change-notifier.md b/src/content/tutorial/state/3-change-notifier.md index 3217758f67e..5150551e5ee 100644 --- a/src/content/tutorial/state/3-change-notifier.md +++ b/src/content/tutorial/state/3-change-notifier.md @@ -2,6 +2,7 @@ title: State management in Flutter description: Instructions on how to manage state with ChangeNotifiers. permalink: /tutorial/change-notifier/ +sitemap: false --- When developers talk about state-management in Flutter, they're @@ -187,4 +188,4 @@ either an article title or an error message, which confirms that your Model and ViewModel are wired up correctly. [ChangeNotifier]: {{site.api}}/flutter/foundation/ChangeNotifier-class.html -[try-catch block]: {{site.dart-site}}/language/error-handling \ No newline at end of file +[try-catch block]: https://dart.dev/language/error-handling diff --git a/src/content/tutorial/state/4-listenable-builder.md b/src/content/tutorial/state/4-listenable-builder.md index 685d96ba666..4c324ec800e 100644 --- a/src/content/tutorial/state/4-listenable-builder.md +++ b/src/content/tutorial/state/4-listenable-builder.md @@ -2,6 +2,7 @@ title: Rebuild UI when state changes description: Instructions on how to manage state with ChangeNotifiers. permalink: /tutorial/listenables/ +sitemap: false --- The view layer is your UI, and in Flutter, that refers to your app's diff --git a/src/content/tutorial/tutorial.11tydata.json b/src/content/tutorial/tutorial.11tydata.json deleted file mode 100644 index abc6c67883f..00000000000 --- a/src/content/tutorial/tutorial.11tydata.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "sitemap": false, - "noindex": true, - "showBreadcrumbs": true, - "extraBodyClass": "tutorial" -} diff --git a/src/content/tutorial/ui-102/1-intro.md b/src/content/tutorial/ui-102/1-intro.md index 9eca3f89d8d..10e48f6549e 100644 --- a/src/content/tutorial/ui-102/1-intro.md +++ b/src/content/tutorial/ui-102/1-intro.md @@ -3,6 +3,7 @@ title: Advanced UI features description: | A gentle introduction into advanced UI features: adaptive layouts, slivers, scrolling, navigation. permalink: /tutorial/set-up-ui-102/ +sitemap: false --- In this third installment of the Flutter tutorial series, you'll use diff --git a/src/content/tutorial/ui-102/2-adaptive-layout.md b/src/content/tutorial/ui-102/2-adaptive-layout.md index ba51a7d1399..4fea309817c 100644 --- a/src/content/tutorial/ui-102/2-adaptive-layout.md +++ b/src/content/tutorial/ui-102/2-adaptive-layout.md @@ -1,7 +1,8 @@ --- -title: LayoutBuilder and adaptive layours +title: LayoutBuilder and adaptive layouts description: Learn how to use the LayoutBuilder widget permalink: /tutorial/adaptive-layouts/ +sitemap: false --- Modern apps need to work well on screens of all sizes. On this page, diff --git a/src/content/tutorial/ui-102/3-slivers.md b/src/content/tutorial/ui-102/3-slivers.md index 84457bfde1e..ee7e27397e8 100644 --- a/src/content/tutorial/ui-102/3-slivers.md +++ b/src/content/tutorial/ui-102/3-slivers.md @@ -2,6 +2,7 @@ title: Advanced scrolling and slivers description: Learn how to implement performant scrolling with slivers. permalink: /tutorial/slivers/ +sitemap: false --- In this lesson, you'll learn about slivers, which are special widgets diff --git a/src/content/tutorial/ui-102/4-navigation.md b/src/content/tutorial/ui-102/4-navigation.md index 371acef4e72..6ff5d12f0ec 100644 --- a/src/content/tutorial/ui-102/4-navigation.md +++ b/src/content/tutorial/ui-102/4-navigation.md @@ -2,7 +2,9 @@ title: Stack-based navigation description: Learn how to navigate from one page to another in a Flutter app permalink: /tutorial/stack-based-navigation/ +sitemap: false --- + Now that you understand slivers and scrolling, you can implement navigation between screens. In this lesson, you'll update the small-screen view such that when a contact group is tapped, it diff --git a/src/content/tutorial/ui/1-create-an-app.md b/src/content/tutorial/ui/1-create-an-app.md index 8c190d233f6..f2fffd8c77d 100644 --- a/src/content/tutorial/ui/1-create-an-app.md +++ b/src/content/tutorial/ui/1-create-an-app.md @@ -2,6 +2,7 @@ title: Create an app description: Instructions on how to create a new Flutter app. permalink: /tutorial/create-an-app/ +sitemap: false --- {%- comment %} diff --git a/src/content/tutorial/ui/2-widget-fundamentals.md b/src/content/tutorial/ui/2-widget-fundamentals.md index 71ec2ba5516..f6322f98a88 100644 --- a/src/content/tutorial/ui/2-widget-fundamentals.md +++ b/src/content/tutorial/ui/2-widget-fundamentals.md @@ -2,6 +2,7 @@ title: Create widgets description: Learn about stateless widgets and how to build your own. permalink: /tutorial/stateless-widgets/ +sitemap: false --- {%- comment %} diff --git a/src/content/tutorial/ui/3-layout.md b/src/content/tutorial/ui/3-layout.md index 8add428e861..7c51bfd4119 100644 --- a/src/content/tutorial/ui/3-layout.md +++ b/src/content/tutorial/ui/3-layout.md @@ -2,6 +2,7 @@ title: Layout description: Learn about common layout widgets in Flutter. permalink: /tutorial/layout/ +sitemap: false --- {%- comment %} TODO(ewindmill) embed video {%- endcomment %} diff --git a/src/content/tutorial/ui/4-devtools.md b/src/content/tutorial/ui/4-devtools.md index bf6711a952c..0410b4ba758 100644 --- a/src/content/tutorial/ui/4-devtools.md +++ b/src/content/tutorial/ui/4-devtools.md @@ -2,6 +2,7 @@ title: DevTools description: Learn to use the Dart DevTools when developing Flutter apps. permalink: /tutorial/devtools/ +sitemap: false --- {%- comment %} TODO(ewindmill) embed video {%- endcomment %} @@ -116,7 +117,7 @@ referred to as the "unbounded constraints" error. Watch the following video to get an understanding of how to spot and resolve this issue. -{% ytEmbed 'jckqXR5CrPI', 'Decoding Flutter: Unbounded height and width' %} + ## The property editor diff --git a/src/content/tutorial/ui/5-user-input.md b/src/content/tutorial/ui/5-user-input.md index 24f611f8d98..e0ec555e486 100644 --- a/src/content/tutorial/ui/5-user-input.md +++ b/src/content/tutorial/ui/5-user-input.md @@ -2,6 +2,7 @@ title: User input description: Accept input from the user with buttons and text fields permalink: /tutorial/user-input/ +sitemap: false --- {%- comment %} TODO(ewindmill) embed video {%- endcomment %} diff --git a/src/content/tutorial/ui/6-stateful-widget.md b/src/content/tutorial/ui/6-stateful-widget.md index 29f150f0aa7..3d37653d55a 100644 --- a/src/content/tutorial/ui/6-stateful-widget.md +++ b/src/content/tutorial/ui/6-stateful-widget.md @@ -2,6 +2,8 @@ title: Stateful widgets description: Learn about StatefulWidgets and rebuilding Flutter UI. permalink: /tutorial/stateful-widget/ +sitemap: false + --- {%- comment %} TODO(ewindmill) embed video {%- endcomment %} diff --git a/src/content/tutorial/ui/7-implicit-animations.md b/src/content/tutorial/ui/7-implicit-animations.md index 551baf2a578..c76865de4c3 100644 --- a/src/content/tutorial/ui/7-implicit-animations.md +++ b/src/content/tutorial/ui/7-implicit-animations.md @@ -2,6 +2,7 @@ title: Simple animations description: Learn the simplest way to implement animations in Flutter. permalink: /tutorial/animations/ +sitemap: false --- Flutter provides a rich set of animation APIs, and the simplest way to diff --git a/src/content/ui/accessibility/ui-design-and-styling.md b/src/content/ui/accessibility/ui-design-and-styling.md index 648b7e48651..b158fb1fbbe 100644 --- a/src/content/ui/accessibility/ui-design-and-styling.md +++ b/src/content/ui/accessibility/ui-design-and-styling.md @@ -29,8 +29,8 @@ template rendered with the default iOS font setting, and with the largest font setting selected in iOS accessibility settings.
    - {% render docs/app-figure.md, image:"a11y/app-regular-fonts.png", caption:"Default font setting", img-class:"simple-border", img-style:"max-height: 480px;" %} - {% render docs/app-figure.md, image:"a11y/app-large-fonts.png", caption:"Largest accessibility font setting", img-class:"simple-border", img-style:"max-height: 480px;" %} + +
    diff --git a/src/content/ui/adaptive-responsive/index.md b/src/content/ui/adaptive-responsive/index.md index 25238d72986..5b9d393b070 100644 --- a/src/content/ui/adaptive-responsive/index.md +++ b/src/content/ui/adaptive-responsive/index.md @@ -70,5 +70,5 @@ responsive design: You might also check out the Google I/O 2024 talk about this subject. -{% ytEmbed 'LeKLGzpsz9I', 'How to build adaptive UI with Flutter' %} + ::: diff --git a/src/content/ui/adaptive-responsive/platform-adaptations.md b/src/content/ui/adaptive-responsive/platform-adaptations.md index 37a0e92ebbf..1c822c4d550 100644 --- a/src/content/ui/adaptive-responsive/platform-adaptations.md +++ b/src/content/ui/adaptive-responsive/platform-adaptations.md @@ -28,8 +28,8 @@ architecture structures on Android and iOS but sharing the same content code, see the [platform_design code samples][]. :::secondary -Preliminary guides addressing case 2 -are being added to the UI components section. +Preliminary guides addressing case 2 +are being added to the UI components section. You can request additional guides by commenting on [issue #8427][8427]. ::: @@ -63,9 +63,9 @@ On **iOS**: transition and is typically used on fullscreen modal pages.
    - {% render docs/app-figure.md, image:"platform-adaptations/navigation-android.webp", img-style:"border-radius: 12px;", caption:"Android page transition", alt:"An animation of the bottom-up page transition on Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/navigation-ios.webp", img-style:"border-radius: 22px;", caption:"iOS push transition", alt:"An animation of the end-start style push page transition on iOS" %} - {% render docs/app-figure.md, image:"platform-adaptations/navigation-ios-modal.webp", img-style:"border-radius: 22px;", caption:"iOS present transition", alt:"An animation of the bottom-up style present page transition on iOS" %} + + +
    [`Navigator.push()`]: {{site.api}}/flutter/widgets/Navigator/push.html @@ -86,8 +86,8 @@ subcomponent on the next or previous page's `CupertinoNavigationBar` or `CupertinoSliverNavigationBar`.
    - {% render docs/app-figure.md, image:"platform-adaptations/android-zoom-animation.png", img-style:"border-radius: 12px;", caption:"Android", alt:"An animation of the page transition on Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/navigation-ios-nav-bar.webp", img-style:"border-radius: 22px;", caption:"iOS Nav Bar", alt:"An animation of the nav bar transitions during a page transition on iOS" %} + +
    [`ZoomPageTransitionsBuilder`]: {{site.api}}/flutter/material/ZoomPageTransitionsBuilder-class.html @@ -104,8 +104,8 @@ On **iOS**, an edge swipe gesture can be used to pop the top route.
    - {% render docs/app-figure.md, image:"platform-adaptations/navigation-android-back.webp", img-style:"border-radius: 12px;", caption:"Android back button", alt:"A page transition triggered by the Android back button" %} - {% render docs/app-figure.md, image:"platform-adaptations/navigation-ios-back.webp", img-style:"border-radius: 22px;", caption:"iOS back swipe gesture", alt:"A page transition triggered by an iOS back swipe gesture" %} + +
    [`WidgetsApp`]: {{site.api}}/flutter/widgets/WidgetsApp-class.html @@ -126,9 +126,9 @@ Therefore iOS gains high speed more gradually but stops less abruptly and is more slippery at slow speeds.
    - {% render docs/app-figure.md, image:"platform-adaptations/scroll-soft.webp", caption:"Soft fling comparison", alt:"A soft fling where the iOS scrollable slid longer at lower speed than Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/scroll-medium.webp", caption:"Medium fling comparison", alt:"A medium force fling where the Android scrollable reaches speed faster and stopped more abruptly after reaching a longer distance" %} - {% render docs/app-figure.md, image:"platform-adaptations/scroll-strong.webp", caption:"Strong fling comparison", alt:"A strong fling where the Android scrollable reaches speed faster and covered significantly more distance" %} + + +
    ### Overscroll behavior @@ -142,8 +142,8 @@ On **iOS**, scrolling past the edge of a scrollable [overscrolls][] with increasing resistance and snaps back.
    - {% render docs/app-figure.md, image:"platform-adaptations/scroll-overscroll.webp", caption:"Dynamic overscroll comparison", alt:"Android and iOS scrollables being flung past their edge and exhibiting platform specific overscroll behavior" %} - {% render docs/app-figure.md, image:"platform-adaptations/scroll-static-overscroll.webp", caption:"Static overscroll comparison", alt:"Android and iOS scrollables being overscrolled from a resting position and exhibiting platform specific overscroll behavior" %} + +
    [overscroll glow indicator]: {{site.api}}/flutter/widgets/GlowingOverscrollIndicator-class.html @@ -157,7 +157,7 @@ and builds more speed with each successive fling. There is no equivalent behavior on Android.
    - {% render docs/app-figure.md, image:"platform-adaptations/scroll-momentum-ios.webp", caption:"iOS scroll momentum", alt:"Repeated scroll flings building momentum on iOS" %} +
    ### Return to top @@ -168,7 +168,7 @@ scroll controller to the top position. There is no equivalent behavior on Android.
    - {% render docs/app-figure.md, image:"platform-adaptations/scroll-tap-to-top-ios.webp", img-style:"border-radius: 22px;", caption:"iOS status bar tap to top", alt:"Tapping the status bar scrolls the primary scrollable back to the top" %} +
    ## Typography @@ -188,14 +188,14 @@ Therefore a fallback font is used when running on Android if the platform is debug-overridden to iOS or the default Cupertino theme is used. -You might choose to adapt the text styling of Material -widgets to match the default text styling on iOS. -You can see widget-specific examples in the +You might choose to adapt the text styling of Material +widgets to match the default text styling on iOS. +You can see widget-specific examples in the [UI Component section](#ui-components).
    - {% render docs/app-figure.md, image:"platform-adaptations/typography-android.png", img-style:"border-radius: 12px;", caption:"Roboto on Android", alt:"Roboto font typography scale on Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/typography-ios.png", img-style:"border-radius: 22px;", caption:"San Francisco on iOS", alt:"San Francisco typography scale on iOS" %} + +
    [default theme]: {{site.repo.flutter}}/blob/main/packages/flutter/lib/src/cupertino/text_theme.dart @@ -211,8 +211,8 @@ The back button is a simple chevron on iOS and has a stem/shaft on Android.
    - {% render docs/app-figure.md, image:"platform-adaptations/iconography-android.png", caption:"Icons on Android", alt:"Android appropriate icons" %} - {% render docs/app-figure.md, image:"platform-adaptations/iconography-ios.png", caption:"Icons on iOS", alt:"iOS appropriate icons" %} + +
    The material library also provides a set of @@ -238,7 +238,7 @@ Scrolling through picker items on iOS triggers a Both the Material and Cupertino Text Input fields support spellcheck and adapt to use the proper spellcheck configuration for the platform, -and the proper spell check menu and highlight colors. +and the proper spell check menu and highlight colors. Flutter also makes the below adaptations while editing the content of text fields to match the current platform. @@ -255,8 +255,8 @@ keyboard to move the cursor in 2D via a floating cursor. This works on both Material and Cupertino text fields.
    - {% render docs/app-figure.md, image:"platform-adaptations/text-keyboard-move-android.webp", caption:"Android space key cursor move", alt:"Moving the cursor via the space key on Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/text-keyboard-move-ios.webp", caption:"iOS 3D Touch drag cursor move", alt:"Moving the cursor via 3D Touch drag on the keyboard on iOS" %} + +
    ### Text selection toolbar @@ -270,8 +270,8 @@ the iOS style selection toolbar is shown when a text selection is made in a text field.
    - {% render docs/app-figure.md, image:"platform-adaptations/text-toolbar-android.png", caption:"Android text selection toolbar", alt:"Android appropriate text toolbar" %} - {% render docs/app-figure.md, image:"platform-adaptations/text-toolbar-ios.png", caption:"iOS text selection toolbar", alt:"iOS appropriate text toolbar" %} + +
    ### Single tap gesture @@ -290,8 +290,8 @@ nearest edge of the word tapped. Collapsed text selections don't have draggable handles on iOS.
    - {% render docs/app-figure.md, image:"platform-adaptations/text-single-tap-android.webp", caption:"Android tap", alt:"Moving the cursor to the tapped position on Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/text-single-tap-ios.webp", caption:"iOS tap", alt:"Moving the cursor to the nearest edge of the tapped word on iOS" %} + +
    ### Long-press gesture @@ -305,8 +305,8 @@ a long press places the cursor at the location of the long press. The selection toolbar is shown upon release.
    - {% render docs/app-figure.md, image:"platform-adaptations/text-long-press-android.webp", caption:"Android long press", alt:"Selecting a word with long press on Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/text-long-press-ios.webp", caption:"iOS long press", alt:"Selecting a position with long press on iOS" %} + +
    ### Long-press drag gesture @@ -318,8 +318,8 @@ With **Material on iOS** or when using **Cupertino**, dragging while holding the long press moves the cursor.
    - {% render docs/app-figure.md, image:"platform-adaptations/text-long-press-drag-android.webp", caption:"Android long-press drag", alt:"Expanding word selection with a long-press drag on Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/text-long-press-drag-ios.webp", caption:"iOS long-press drag", alt:"Moving the cursor with a long-press drag on iOS" %} + +
    ### Double tap gesture @@ -329,30 +329,30 @@ a double tap selects the word receiving the double tap and shows the selection toolbar.
    - {% render docs/app-figure.md, image:"platform-adaptations/text-double-tap-android.webp", caption:"Android double tap", alt:"Selecting a word via double tap on Android" %} - {% render docs/app-figure.md, image:"platform-adaptations/text-double-tap-ios.webp", caption:"iOS double tap", alt:"Selecting a word via double tap on iOS" %} + +
    ## UI components -This section includes preliminary recommendations on how to adapt -Material widgets to deliver a natural and compelling experience on iOS. -Your feedback is welcomed on [issue #8427][8427]. +This section includes preliminary recommendations on how to adapt +Material widgets to deliver a natural and compelling experience on iOS. +Your feedback is welcomed on [issue #8427][8427]. [8427]: {{site.repo.this}}/issues/8427 ### Widgets with .adaptive() constructors -Several widgets support `.adaptive()` constructors. +Several widgets support `.adaptive()` constructors. The following table lists these widgets. -Adaptive constructors substitute the corresponding Cupertino components -when the app is run on an iOS device. +Adaptive constructors substitute the corresponding Cupertino components +when the app is run on an iOS device. -Widgets in the following table are used primarily for input, -selection, and to display system information. +Widgets in the following table are used primarily for input, +selection, and to display system information. Because these controls are tightly integrated with the operating system, users have been trained to recognize and respond to them. -Therefore, we recommend that you follow platform conventions. +Therefore, we recommend that you follow platform conventions. | Material widget | Cupertino widget | Adaptive constructor | @@ -375,22 +375,22 @@ Therefore, we recommend that you follow platform conventions. ### Top app bar and navigation bar -Since Android 12, the default UI for top app -bars follows the design guidelines defined in [Material 3][mat-appbar]. -On iOS, an equivalent component called "Navigation Bars" +Since Android 12, the default UI for top app +bars follows the design guidelines defined in [Material 3][mat-appbar]. +On iOS, an equivalent component called "Navigation Bars" is defined in [Apple's Human Interface Guidelines][hig-appbar] (HIG).
    - {% render docs/app-figure.md, image:"platform-adaptations/mat-appbar.png", caption:"Top App Bar in Material 3", alt:"Top App Bar in Material 3", height: "240px" %} - {% render docs/app-figure.md, image:"platform-adaptations/hig-appbar.png", caption:"Navigation Bar in Human Interface Guidelines", alt:"Navigation Bar in Human Interface Guidelines", height: "240px" %} + +
    -Certain properties of app bars in Flutter apps should be adapted, -like system icons and page transitions. -These are already automatically adapted when using -the Material `AppBar` and `SliverAppBar` widgets. -You can also further customize the properties of these widgets to better -match iOS platform styles, as shown below. +Certain properties of app bars in Flutter apps should be adapted, +like system icons and page transitions. +These are already automatically adapted when using +the Material `AppBar` and `SliverAppBar` widgets. +You can also further customize the properties of these widgets to better +match iOS platform styles, as shown below. ```dart // Map the text theme to iOS styles @@ -420,11 +420,11 @@ AppBar( ), ``` -But, because app bars are displayed alongside -other content in your page, it's only recommended to adapt the styling -so long as it's cohesive with the rest of your application. You can see -additional code samples and a further explanation in -[the GitHub discussion on app bar adaptations][appbar-post]. +But, because app bars are displayed alongside +other content in your page, it's only recommended to adapt the styling +so long as it's cohesive with the rest of your application. You can see +additional code samples and a further explanation in +[the GitHub discussion on app bar adaptations][appbar-post]. [mat-appbar]: {{site.material}}/components/top-app-bar/overview [hig-appbar]: {{site.apple-dev}}/design/human-interface-guidelines/components/navigation-and-search/navigation-bars/ @@ -432,25 +432,25 @@ additional code samples and a further explanation in ### Bottom navigation bars -Since Android 12, the default UI for bottom navigation -bars follow the design guidelines defined in [Material 3][mat-navbar]. -On iOS, an equivalent component called "Tab Bars" +Since Android 12, the default UI for bottom navigation +bars follow the design guidelines defined in [Material 3][mat-navbar]. +On iOS, an equivalent component called "Tab Bars" is defined in [Apple's Human Interface Guidelines][hig-tabbar] (HIG).
    - {% render docs/app-figure.md, image:"platform-adaptations/mat-navbar.png", caption:"Bottom Navigation Bar in Material 3", alt:"Bottom Navigation Bar in Material 3", height: "160px" %} - {% render docs/app-figure.md, image:"platform-adaptations/hig-tabbar.png", caption:"Tab Bar in Human Interface Guidelines", alt:"Tab Bar in Human Interface Guidelines", height: "160px" %} + +
    Since tab bars are persistent across your app, they should match your -own branding. However, if you choose to use Material's default +own branding. However, if you choose to use Material's default styling on Android, you might consider adapting to the default iOS tab bars. -To implement platform-specific bottom navigation bars, -you can use Flutter's `NavigationBar` widget on Android -and the `CupertinoTabBar` widget on iOS. -Below is a code snippet you can +To implement platform-specific bottom navigation bars, +you can use Flutter's `NavigationBar` widget on Android +and the `CupertinoTabBar` widget on iOS. +Below is a code snippet you can adapt to show a platform-specific navigation bars. ```dart @@ -499,20 +499,20 @@ Scaffold( ### Text fields Since Android 12, text fields follow the -[Material 3][m3-text-field] (M3) design guidelines. +[Material 3][m3-text-field] (M3) design guidelines. On iOS, Apple's [Human Interface Guidelines][hig-text-field] (HIG) define an equivalent component.
    - {% render docs/app-figure.md, image:"platform-adaptations/m3-text-field.png", caption:"Text Field in Material 3", alt:"Text Field in Material 3", width:"320px", height:"100px" %} - {% render docs/app-figure.md, image:"platform-adaptations/hig-text-field.png", caption:"Text Field in HIG", alt:"Text Field in Human Interface Guidelines", width:"320px", height:"100px" %} + +
    -Since text fields require user input, -their design should follow platform conventions. +Since text fields require user input, +their design should follow platform conventions. -To implement a platform-specific `TextField` -in Flutter, you can adapt the styling of the +To implement a platform-specific `TextField` +in Flutter, you can adapt the styling of the Material `TextField`. ```dart @@ -542,7 +542,7 @@ Widget _createAdaptiveTextField() { } ``` -To learn more about adapting text fields, check out +To learn more about adapting text fields, check out [the GitHub discussion on text fields][text-field-post]. You can leave feedback or ask questions in the discussion. diff --git a/src/content/ui/animations/hero-animations.md b/src/content/ui/animations/hero-animations.md index c3ec7619329..e8f5bbc5613 100644 --- a/src/content/ui/animations/hero-animations.md +++ b/src/content/ui/animations/hero-animations.md @@ -23,7 +23,7 @@ motion is sometimes referred to as a _shared element transition_. You might want to watch this one-minute video introducing the Hero widget: -{% ytEmbed 'Be9UH1kXFDw', 'Hero | Flutter widget of the week' %} + This guide demonstrates how to build standard hero animations, and hero animations that transform the image from a circular shape to a square shape @@ -67,7 +67,7 @@ Tapping the flippers in the blue route (or using the device's back-to-previous-route gesture) flies the flippers back to the original route. -{% ytEmbed 'CEcFnqRDfgw', 'Standard hero animation in Flutter' %} + **Radial hero animations**
    @@ -82,7 +82,7 @@ that displays it with a square shape. Tapping the square image flies the hero back to the original route, displayed with a circular shape. -{% ytEmbed 'LWKENpwDKiM', 'Radial hero animation in Flutter' %} + Before moving to the sections specific to [standard](#standard-hero-animations) @@ -286,7 +286,7 @@ The custom PhotoHero class maintains the hero, and its size, image, and behavior when tapped. The PhotoHero builds the following widget tree: -{% render docs/app-figure.md, image:"ui/animations/photohero-class.png", alt:"PhotoHero class widget tree %} + Here's the code: @@ -548,7 +548,7 @@ with a rectangular clip (that remains a constant size throughout). To do this, it builds the following widget tree: -{% render docs/app-figure.md, image:"ui/animations/radial-expansion-class.png", alt:"RadialExpansion widget tree" %} + Here's the code: diff --git a/src/content/ui/animations/implicit-animations.md b/src/content/ui/animations/implicit-animations.md index 83be04e6482..50fea233c3e 100644 --- a/src/content/ui/animations/implicit-animations.md +++ b/src/content/ui/animations/implicit-animations.md @@ -37,9 +37,9 @@ that every Flutter dev needs to know from top to bottom. The following videos cover topics that are relevant to implicit animations. -{% ytEmbed 'IVTjpW3W33s', 'Flutter implicit animation basics' %} + -{% ytEmbed '6KiPEqzJIKQ', 'Create custom implicit animations with TweenAnimationBuilder' %} + ## The Boring Show @@ -47,7 +47,7 @@ Watch the Boring Show to follow Google Engineers build apps from scratch in Flutter. The following episode covers using implicit animations in a news aggregator app. -{% ytEmbed '8ehlWchLVlQ', 'Adding implicit animations to a news application' %} + ## Widget of the Week videos @@ -65,7 +65,7 @@ implicitly animated widgets: {% assign videoUrl = animatedUrls[forloop.index0] %} {% assign videoDescription = 'Learn about the ' | append: widget | append: ' Flutter Widget' %} -{% ytEmbed videoUrl, videoDescription %} + {% endfor -%} diff --git a/src/content/ui/animations/index.md b/src/content/ui/animations/index.md index 17fba191818..39c6d4986a0 100644 --- a/src/content/ui/animations/index.md +++ b/src/content/ui/animations/index.md @@ -20,7 +20,7 @@ To help you decide, check out the video, [How to choose which Flutter Animation Widget is right for you?][] (Also published as a [_companion article_][article1].) -{% ytEmbed 'GXIJJkq_H8g', 'How to choose which Flutter animation widget is right for your use case' %} + (To dive deeper into the decision process, watch the [Animations in Flutter done right][] video, @@ -38,7 +38,7 @@ For a deeper understanding of just how animations work in Flutter, watch [Animation deep dive][]. (Also published as a [_companion article_][article6].) -{% ytEmbed 'PbcILiN8rbo', 'Take a deep dive into Flutter animation' %} + ## Implicit and explicit animations @@ -49,7 +49,7 @@ to implement) suits your needs, watch [Animation basics with implicit animations][]. (Also published as a [_companion article_][article2].) -{% ytEmbed 'IVTjpW3W33s', 'Flutter implicit animation basics' %} + ### Custom implicit animations @@ -57,7 +57,7 @@ To create a custom implicit animation, watch [Creating your own custom implicit animations with TweenAnimationBuilder][]. (Also published as a [_companion article_][article3].) -{% ytEmbed '6KiPEqzJIKQ', 'Create custom implicit animations with TweenAnimationBuilder' %} + ### Built-in implicit animations @@ -69,7 +69,7 @@ For more information, watch built-in explicit animations][]. (Also published as a [_companion article_][article4].) -{% ytEmbed 'CunyH6unILQ', 'Making your first directional animations with built-in explicit animations' %} + ### Explicit animations @@ -78,7 +78,7 @@ If you need to build an explicit animation from scratch, watch AnimatedBuilder and AnimatedWidget][]. (Also published as a [_companion article_][article5].) -{% ytEmbed 'fneC7t4R_B0', 'Creating custom explicit animations with AnimatedBuilder and AnimatedWidget' %} + ## Animation types diff --git a/src/content/ui/animations/staggered-animations.md b/src/content/ui/animations/staggered-animations.md index c31cd6a91c8..813cc647b60 100644 --- a/src/content/ui/animations/staggered-animations.md +++ b/src/content/ui/animations/staggered-animations.md @@ -56,7 +56,7 @@ staggered_pic_selection. The following video demonstrates the animation performed by basic_staggered_animation: -{% ytEmbed '0fFvnZemmh8', 'Staggered animation example' %} + In the video, you see the following animation of a single widget, which begins as a bordered blue square with slightly rounded corners. diff --git a/src/content/ui/animations/tutorial.md b/src/content/ui/animations/tutorial.md index cd68e051681..2738c5300fe 100644 --- a/src/content/ui/animations/tutorial.md +++ b/src/content/ui/animations/tutorial.md @@ -92,7 +92,7 @@ The changes from the non-animated example are highlighted: + class _LogoAppState extends State with SingleTickerProviderStateMixin { + late Animation animation; + late AnimationController controller; -+ ++ + @override + void initState() { + super.initState(); @@ -106,7 +106,7 @@ The changes from the non-animated example are highlighted: + }); + controller.forward(); + } -+ ++ @override Widget build(BuildContext context) { return Center( @@ -120,7 +120,7 @@ The changes from the non-animated example are highlighted: ), ); } -+ ++ + @override + void dispose() { + controller.dispose(); @@ -172,7 +172,7 @@ check out [Cascade notation][] in the [Dart language documentation][]. ::: -## Simplifying with Animated­Widget +## Simplifying with AnimatedWidget :::secondary What's the point? * How to use the [`AnimatedWidget`][] helper class @@ -231,7 +231,7 @@ and it passes the `Animation` object to `AnimatedLogo`: + class AnimatedLogo extends AnimatedWidget { + const AnimatedLogo({super.key, required Animation animation}) + : super(listenable: animation); -+ ++ + @override + Widget build(BuildContext context) { + final animation = listenable as Animation; @@ -245,7 +245,7 @@ and it passes the `Animation` object to `AnimatedLogo`: + ); + } + } -+ ++ class LogoApp extends StatefulWidget { // ... @@ -276,7 +276,7 @@ and it passes the `Animation` object to `AnimatedLogo`: - ); - } + Widget build(BuildContext context) => AnimatedLogo(animation: animation); - + // ... } ``` @@ -390,7 +390,7 @@ dirty as necessary, so you don't need to call `addListener()`. The widget tree for the [animate4][] example looks like this: -{% render docs/app-figure.md, image:"ui/AnimatedBuilder-WidgetTree.png", alt:"AnimatedBuilder widget tree" %} + Starting from the bottom of the widget tree, the code for rendering the logo is straightforward: @@ -472,10 +472,10 @@ in the bullet points above. ```dart diff void main() => runApp(const LogoApp()); - + + class LogoWidget extends StatelessWidget { + const LogoWidget({super.key}); -+ ++ + // Leave out the height and width so it fills the animating parent. + @override + Widget build(BuildContext context) { @@ -485,17 +485,17 @@ in the bullet points above. + ); + } + } -+ ++ + class GrowTransition extends StatelessWidget { + const GrowTransition({ + required this.child, + required this.animation, + super.key, + }); -+ ++ + final Widget child; + final Animation animation; -+ ++ + @override + Widget build(BuildContext context) { + return Center( diff --git a/src/content/ui/design/cupertino/index.md b/src/content/ui/design/cupertino/index.md index b53574788c1..111b1f11329 100644 --- a/src/content/ui/design/cupertino/index.md +++ b/src/content/ui/design/cupertino/index.md @@ -13,7 +13,7 @@ They also include iOS interactions and animations. The following 15-minute video provides a high-level glimpse of the Cupertino package: -{% ytEmbed '3PdUaidHc-E', 'Flutter\'s Cupertino Package' %} + To see some Cupertino widgets in action, the following videos from the Widget of the Week series cover a few of them. @@ -21,27 +21,27 @@ Widget of the Week series cover a few of them.
    - {% ytEmbed 'D0xwcz2IqAY', 'CupertinoRadio (Widget of the Week)' %} +
    - {% ytEmbed '5H-WvH5O29I', 'CupertinoSheetRoute (Widget of the Week)' %} +
    - {% ytEmbed 'esnBf6V4C34', 'CupertinoSlidingSegmentedControl (Widget of the Week)' %} +
    - {% ytEmbed 'ua54JU7k1Us', 'CupertinoCheckbox (Widget of the Week)' %} +
    - {% ytEmbed '24tg_N4sdMQ', 'CupertinoSwitch (Widget of the Week)' %} +
    diff --git a/src/content/ui/design/text/typography.md b/src/content/ui/design/text/typography.md index a0c11079b29..33ab1baead8 100644 --- a/src/content/ui/design/text/typography.md +++ b/src/content/ui/design/text/typography.md @@ -148,7 +148,7 @@ of Flutter's typography and combines it with the Material _and_ Cupertino look and feel (depending on the platform the app runs on), animation, and custom fragment shaders: -{% ytEmbed 'sA5MRFFUuOU', 'Prototyping beautiful designs with Flutter' %} + To read one engineer's experience customizing variable fonts and animating them as they diff --git a/src/content/ui/index.md b/src/content/ui/index.md index 5a9dd546965..96c02bb91c5 100644 --- a/src/content/ui/index.md +++ b/src/content/ui/index.md @@ -2,9 +2,6 @@ title: Building user interfaces with Flutter shortTitle: UI description: Introduction to user interface development in Flutter. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- diff --git a/src/content/ui/interactivity/actions-and-shortcuts.md b/src/content/ui/interactivity/actions-and-shortcuts.md index 262a9195fad..790ed9d75fa 100644 --- a/src/content/ui/interactivity/actions-and-shortcuts.md +++ b/src/content/ui/interactivity/actions-and-shortcuts.md @@ -1,9 +1,6 @@ --- title: Using Actions and Shortcuts description: How to use Actions and Shortcuts in your Flutter app. -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- This page describes how to bind physical keyboard events to actions in the user diff --git a/src/content/ui/interactivity/focus.md b/src/content/ui/interactivity/focus.md index 6ffe422f9bd..83c54019847 100644 --- a/src/content/ui/interactivity/focus.md +++ b/src/content/ui/interactivity/focus.md @@ -420,7 +420,7 @@ your custom controls. To learn more, watch this short Widget of the Week video on the `FocusableActionDetector` widget: -{% ytEmbed 'R84AGg0lKs8', 'FocusableActionDetector - Flutter widget of the week' %} + ::: ## Controlling focus traversal diff --git a/src/content/ui/interactivity/gestures/index.md b/src/content/ui/interactivity/gestures/index.md index 208b3c23b88..7f3d89e4369 100644 --- a/src/content/ui/interactivity/gestures/index.md +++ b/src/content/ui/interactivity/gestures/index.md @@ -153,7 +153,7 @@ use a [`GestureDetector`][]. To learn more, watch this short Widget of the Week video on the `GestureDetector` widget: -{% ytEmbed 'WhVXkCFPmK4', 'GestureDetector - Flutter widget of the week' %} + ::: If you're using Material Components, diff --git a/src/content/ui/interactivity/index.md b/src/content/ui/interactivity/index.md index 25d06c06f4b..0103637f9a5 100644 --- a/src/content/ui/interactivity/index.md +++ b/src/content/ui/interactivity/index.md @@ -22,7 +22,7 @@ stateless widgets. The [building layouts tutorial][] showed you how to create the layout for the following screenshot. -{% render docs/app-figure.md, img-class:"site-mobile-screenshot border", image:"ui/layout/lakes.jpg", caption:"The layout tutorial app" %} + When the app first launches, the star is solid red, indicating that this lake has previously been favorited. @@ -33,7 +33,7 @@ replacing the solid star with an outline and decreasing the count. Tapping again favorites the lake, drawing a solid star and increasing the count. -{% render docs/app-figure.md, image:"ui/favorited-not-favorited.png", alt:"The custom widget you'll create", img-class:"diagram-wrap" %} + To accomplish this, you'll create a single custom widget that includes both the star and the count, diff --git a/src/content/ui/layout/constraints.md b/src/content/ui/layout/constraints.md index d3766759d3a..d0bddae50ce 100644 --- a/src/content/ui/layout/constraints.md +++ b/src/content/ui/layout/constraints.md @@ -2,9 +2,6 @@ title: Understanding constraints description: Flutter's model for widget constraints, sizing, positioning, and how they interact. showToc: false -js: - - defer: true - url: /assets/js/inject_dartpad.dart.js --- @@ -2205,5 +2202,5 @@ header image at the top of the article. To better understand how Flutter implements layout constraints, check out the following 5-minute video: -{% ytEmbed 'jckqXR5CrPI', 'Decoding Flutter: Unbounded height and width' %} + ::: diff --git a/src/content/ui/layout/index.md b/src/content/ui/layout/index.md index 7e97270da4a..1c4e631ab7e 100644 --- a/src/content/ui/layout/index.md +++ b/src/content/ui/layout/index.md @@ -154,9 +154,9 @@ displays the widget.
    -{% tabs "app-type-tabs", true %} + -{% tab "Standard apps" %} + For a general app, you can add the `Container` widget to the app's `build()` method: @@ -189,9 +189,9 @@ general app, you have to build them yourself. This app changes the background color to white and the text to dark grey to mimic a Material app. -{% endtab %} + -{% tab "Material apps" %} + For a `Material` app, you can use a [`Scaffold`][] widget; it provides a default banner, background color, @@ -230,9 +230,9 @@ libraries, you can customize existing widgets, or you can build your own set of custom widgets. ::: -{% endtab %} + -{% tab "Cupertino apps" %} + To create a `Cupertino` app, use the `CupertinoApp` and [`CupertinoPageScaffold`][] widgets. @@ -293,9 +293,9 @@ You can mix widgets from both libraries, you can customize existing widgets, or you can build your own set of custom widgets. ::: -{% endtab %} + -{% endtabs %} + [`CupertinoColors`]: {{site.api}}/flutter/cupertino/CupertinoColors-class.html [`CupertinoPageScaffold`]: {{site.api}}/flutter/cupertino/CupertinoPageScaffold-class.html @@ -322,7 +322,7 @@ App source code: * [Non-Material app]({{site.repo.this}}/tree/main/examples/layout/non_material)
    -{% render docs/app-figure.md, image:"ui/layout/hello-world.png", alt:"Screenshot of app displaying Hello World", img-style:"max-height: 400px;" %} +

    @@ -770,9 +770,9 @@ only Material apps can use the Material Components library. -{% tabs "widget-types-tabs", true %} + -{% tab "Standard widgets" %} + [`Container`](#container) : Adds padding, margins, borders, @@ -787,9 +787,9 @@ only Material apps can use the Material Components library. [`Stack`](#stack) : Overlaps a widget on top of another. -{% endtab %} + -{% tab "Material widgets" %} + [`Scaffold`][] : Provides a structured layout framework @@ -807,9 +807,9 @@ only Material apps can use the Material Components library. : Organizes up to 3 lines of text, and optional leading and trailing icons, into a row. -{% endtab %} + -{% tab "Cupertino widgets" %} + [`CupertinoPageScaffold`][] : Provides the basic layout structure for an iOS-style page. @@ -823,9 +823,9 @@ only Material apps can use the Material Components library. [`CupertinoTabBar`][] and [`CupertinoTabScaffold`][] : Creates the characteristic iOS bottom tab bar. -{% endtab %} + -{% endtabs %} + [`Scaffold`]: {{site.api}}/flutter/material/Scaffold-class.html [`AppBar`]: {{site.api}}/flutter/material/AppBar-class.html @@ -1315,9 +1315,9 @@ The following videos, part of the [Flutter in Focus][] series, explain `Stateless` and `Stateful` widgets. -{% ytEmbed 'wE7khGHVkYY', 'How to create stateless widgets' %} + -{% ytEmbed 'AqCMFXEmf3w', 'How and when stateful widgets are best used' %} + [Flutter in Focus playlist]({{site.yt.playlist}}PLjxrf2q8roU2HdJQDjJzOeO6J3FoFLWr2) @@ -1326,7 +1326,7 @@ explain `Stateless` and `Stateful` widgets. Each episode of the [Widget of the Week series][] focuses on a widget. Several of them include layout widgets. -{% ytEmbed 'b_sQ9bMltGU', 'Introducing widget of the week' %} + [Flutter Widget of the Week playlist]({{site.yt.playlist}}PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG) diff --git a/src/content/ui/layout/scrolling/index.md b/src/content/ui/layout/scrolling/index.md index 6ac0569da0b..b72c12e54b1 100644 --- a/src/content/ui/layout/scrolling/index.md +++ b/src/content/ui/layout/scrolling/index.md @@ -18,9 +18,9 @@ child when necessary. Other useful widgets include You can check out more of these widgets on the [scrolling page][] of the Widget catalog. -{% ytEmbed 'DbkIQSvwnZc', 'Scrollbar | Flutter widget of the week' %} + -{% ytEmbed 'KJpkjHGiI5A', 'ListView | Flutter widget of the week' %} + ### Infinite scrolling @@ -42,11 +42,11 @@ specific scrolling behavior. A video on using [`DraggableScrollableSheet`][]: -{% ytEmbed 'Hgw819mL_78', 'DraggableScrollableSheet | Flutter widget of the week' %} + Turn the scrollable area into a wheel with [`ListWheelScrollView`][]! -{% ytEmbed 'dUhmWAz4C7Y', 'ListWheelScrollView | Flutter widget of the week' %} + [`DraggableScrollableSheet`]: {{site.api}}/flutter/widgets/DraggableScrollableSheet-class.html [`GridView`]: {{site.api}}/flutter/widgets/GridView-class.html @@ -93,4 +93,4 @@ or do you use a sliver? Check out the "ShrinkWrap vs Slivers" video: -{% ytEmbed 'LUqDNnv_dh0', 'ShrinkWrap vs Slivers | Decoding Flutter' %} + diff --git a/src/content/ui/layout/scrolling/slivers.md b/src/content/ui/layout/scrolling/slivers.md index 5cd81e461ed..48f6d7de3e3 100644 --- a/src/content/ui/layout/scrolling/slivers.md +++ b/src/content/ui/layout/scrolling/slivers.md @@ -14,7 +14,7 @@ such as elastic scrolling. For a free, instructor-led video workshop that uses DartPad, check out the following video about using slivers. -{% ytEmbed 'YY-_yrZdjGc', 'Building scrolling experiences in Flutter' %} + ## Resources @@ -31,21 +31,21 @@ in Flutter, see the following resources: video that gives an overview of the `SliverAppBar` widget. - {% ytEmbed 'R9C5KMJKluE', 'SliverAppBar | Flutter widget of the week' %} + **[SliverList and SliverGrid][]** : A one-minute Widget-of-the-week video that gives an overview of the `SliverList` and `SliverGrid` widgets. - {% ytEmbed 'ORiTTaVY6mM', 'SliverList & SliverGrid | Flutter widget of the week' %} + **[Slivers explained - Making dynamic layouts][]** : A 50-minute episode of [The Boring Show][] where Ian Hickson, Flutter's Tech Lead, and Filip Hracek discuss the power of slivers. - {% ytEmbed 'Mz3kHQxBjGg', 'Slivers explained - Making dynamic layouts' %} + ## API docs diff --git a/src/content/ui/layout/tutorial.md b/src/content/ui/layout/tutorial.md index c49b1467421..fde2e8d2030 100644 --- a/src/content/ui/layout/tutorial.md +++ b/src/content/ui/layout/tutorial.md @@ -16,7 +16,7 @@ This tutorial explains how to design and build layouts in Flutter. If you use the example code provided, you can build the following app. -{% render docs/app-figure.md, img-class:"site-mobile-screenshot border", image:"ui/layout/layout-demo-app.png", caption:"The finished app.", width:"50%" %} +
    @@ -64,7 +64,7 @@ Ask these questions to break the layout down to its basic elements. Identify the larger elements. In this example, you arrange the image, title, buttons, and description into a column. -{% render docs/app-figure.md, img-class:"site-mobile-screenshot border", image:"ui/layout/layout-sketch-intro.svg", caption:"Major elements in the layout: image, row, row, and text block", width:"50%" %} +
  1. @@ -80,7 +80,7 @@ a column of text, a star icon, and a number. Its first child, the column, contains two lines of text. That first column might need more space. -{% render docs/app-figure.md, image:"ui/layout/layout-sketch-title-block.svg", caption:"Title section with text blocks and an icon" -%} +
  2. @@ -89,7 +89,7 @@ That first column might need more space. Row 2, the **Button** section, has three children: each child contains a column which then contains an icon and text. -{% render docs/app-figure.md, image:"ui/layout/layout-sketch-button-block.svg", caption:"The Button section with three labeled buttons", width:"50%" %} + @@ -162,7 +162,7 @@ the following layout. -{% render docs/app-figure.md, image:"ui/layout/layout-sketch-title-block-unlabeled.svg", caption:"The Title section as sketch and prototype UI" %} + ### Add the `TitleSection` Widget @@ -282,7 +282,7 @@ In this section, add the buttons that will add functionality to your app. The **Button** section contains three columns that use the same layout: an icon over a row of text. -{% render docs/app-figure.md, image:"ui/layout/layout-sketch-button-block-unlabeled.svg", caption:"The Button section as sketch and prototype UI" %} + Plan to distribute these columns in one row so each takes the same amount of space. Paint all text and icons with the primary color. @@ -436,7 +436,7 @@ Add the button section to the `children` list. In this section, add the text description to this app. -{% render docs/app-figure.md, image:"ui/layout/layout-sketch-add-text-block.svg", caption:"The text block as sketch and prototype UI" %} + @@ -486,7 +486,7 @@ the text of the location description. + 'degrees Celsius in the summer. Activities enjoyed here ' + 'include rowing, and riding the summer toboggan run.', + ), - ], + ], ``` ## Add the Image section @@ -571,7 +571,7 @@ Set the `image` property to the path of the image you added in That's it! When you hot reload the app, your app should look like this. -{% render docs/app-figure.md, img-class:"site-mobile-screenshot border", image:"ui/layout/layout-demo-app.png", caption:"The finished app", width:"50%" %} + ## Resources diff --git a/src/content/ui/navigation/deep-linking.md b/src/content/ui/navigation/deep-linking.md index 32fdb219e03..cbbaaa5052e 100644 --- a/src/content/ui/navigation/deep-linking.md +++ b/src/content/ui/navigation/deep-linking.md @@ -33,7 +33,7 @@ the pattern: `/#/path/to/app/screen`, but this can be changed by If you are a visual learner, check out the following video: -{% ytEmbed 'KNAb2XL7k2g', 'Deep linking in Flutter' %} + ## Get started diff --git a/src/content/ui/widgets/accessibility.md b/src/content/ui/widgets/accessibility.md index 052330b6b67..2defdab4e64 100644 --- a/src/content/ui/widgets/accessibility.md +++ b/src/content/ui/widgets/accessibility.md @@ -2,6 +2,6 @@ title: Accessibility widgets shortTitle: Accessibility description: A catalog of Flutter's accessibility widgets. +widgetCategory: Accessibility +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Accessibility", catalog:catalog %} diff --git a/src/content/ui/widgets/animation.md b/src/content/ui/widgets/animation.md index 1ae8dc18827..8641dddee0d 100644 --- a/src/content/ui/widgets/animation.md +++ b/src/content/ui/widgets/animation.md @@ -2,6 +2,6 @@ title: Animation and motion widgets shortTitle: Animation description: A catalog of Flutter's animation widgets. +widgetCategory: Animation and motion +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Animation and motion", catalog:catalog %} diff --git a/src/content/ui/widgets/assets.md b/src/content/ui/widgets/assets.md index c6f3c32decf..359653407f3 100644 --- a/src/content/ui/widgets/assets.md +++ b/src/content/ui/widgets/assets.md @@ -2,6 +2,6 @@ title: Assets, images, and icon widgets shortTitle: Assets description: A catalog of Flutter's asset widgets. +widgetCategory: Assets, images, and icons +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Assets, images, and icons", catalog:catalog %} diff --git a/src/content/ui/widgets/async.md b/src/content/ui/widgets/async.md index 5f963ad27bd..a7b399746d4 100644 --- a/src/content/ui/widgets/async.md +++ b/src/content/ui/widgets/async.md @@ -2,6 +2,6 @@ title: Async widgets shortTitle: Async description: A catalog of Flutter widgets for handling asynchronous code. +widgetCategory: Async +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Async", catalog:catalog %} diff --git a/src/content/ui/widgets/basics.md b/src/content/ui/widgets/basics.md index 6203e1f3f87..8d64c710048 100644 --- a/src/content/ui/widgets/basics.md +++ b/src/content/ui/widgets/basics.md @@ -2,6 +2,6 @@ title: Basic widgets shortTitle: Basics description: A catalog of Flutter's basic widgets. +widgetCategory: Basics +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Basics", catalog:catalog %} diff --git a/src/content/ui/widgets/cupertino.md b/src/content/ui/widgets/cupertino.md index c3736b99a79..59453d3aaec 100644 --- a/src/content/ui/widgets/cupertino.md +++ b/src/content/ui/widgets/cupertino.md @@ -2,10 +2,8 @@ title: Cupertino widgets shortTitle: Cupertino description: > - A catalog of Flutter's cupertino widgets that align with + A catalog of Flutter's Cupertino widgets that align with Apple's Human Interface Guidelines for iOS and macOS. +widgetCategory: Cupertino +layout: widget-catalog-page --- - -{{< youtube D0xwcz2IqAY >}} - -{% render docs/catalog-page.md, categoryName:"Cupertino", catalog:catalog %} diff --git a/src/content/ui/widgets/index.md b/src/content/ui/widgets/index.md index 4251e78d498..1a640246125 100644 --- a/src/content/ui/widgets/index.md +++ b/src/content/ui/widgets/index.md @@ -14,10 +14,10 @@ you can also see all the widgets in the [widget index][]. Flutter ships with two design systems as part of the SDK.
    -{% assign categories = catalog.index | sort: 'name' -%} +{% assign categories = catalog.index | sortBy: 'name' -%} {% for section in categories %} {%- if section.name == "Cupertino" or section.name == "Material components" -%} - +
    {{section.name}}
    @@ -41,10 +41,10 @@ Base widgets support a range of common rendering options like input, layout, and text.
    -{% assign categories = catalog.index | sort: 'name' -%} +{% assign categories = catalog.index | sortBy: 'name' -%} {% for section in categories %} {%- if section.name != "Cupertino" and section.name != "Material components" and section.name != "Material 2 components" -%} - +
    {{section.name}}
    @@ -64,32 +64,32 @@ help you quickly get started with Flutter widgets.
    - {% ytEmbed 'D0xwcz2IqAY', 'CupertinoRadio - Flutter widget of the week', true %} +
    - {% ytEmbed '5H-WvH5O29I', 'CupertinoSheetRoute - Flutter widget of the week', true %} +
    - {% ytEmbed 'esnBf6V4C34', 'CupertinoSlidingSegmentedControl - Flutter widget of the week', true %} +
    - {% ytEmbed 'ua54JU7k1Us', 'CupertinoCheckbox - Flutter widget of the week', true %} +
    - {% ytEmbed '24tg_N4sdMQ', 'CupertinoSwitch - Flutter widget of the week', true %} +
    - {% ytEmbed 'GQ8ajYVF0bo', 'CarouselView - Flutter widget of the week', true %} +
    diff --git a/src/content/ui/widgets/input.md b/src/content/ui/widgets/input.md index d331910aa29..34568a0484b 100644 --- a/src/content/ui/widgets/input.md +++ b/src/content/ui/widgets/input.md @@ -2,6 +2,6 @@ title: Input widgets shortTitle: Input description: A catalog of Flutter's input widgets. +widgetCategory: Input +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Input", catalog:catalog %} diff --git a/src/content/ui/widgets/interaction.md b/src/content/ui/widgets/interaction.md index 8ca4ed62f6f..cfe215762a7 100644 --- a/src/content/ui/widgets/interaction.md +++ b/src/content/ui/widgets/interaction.md @@ -1,8 +1,8 @@ --- title: Interaction model widgets shortTitle: Interaction -description: > +description: > A catalog of Flutter's widgets supporting user interaction and navigation. +widgetCategory: Interaction models +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Interaction models", catalog:catalog %} diff --git a/src/content/ui/widgets/layout.md b/src/content/ui/widgets/layout.md index 11a51fa6ac0..7b16b6c2113 100644 --- a/src/content/ui/widgets/layout.md +++ b/src/content/ui/widgets/layout.md @@ -2,6 +2,6 @@ title: Layout widgets shortTitle: Layout description: A catalog of Flutter's widgets for building layouts. +widgetCategory: Layout +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Layout", catalog:catalog %} diff --git a/src/content/ui/widgets/material.md b/src/content/ui/widgets/material.md index 8bd37d0bb3b..97d0752b8bb 100644 --- a/src/content/ui/widgets/material.md +++ b/src/content/ui/widgets/material.md @@ -1,8 +1,11 @@ --- title: Material component widgets shortTitle: Material -description: > +description: > A catalog of Flutter's widgets implementing Material 3 design guidelines. +widgetCategory: Material components +materialCatalog: true +layout: widget-catalog-page --- Flutter provides a variety of visual, behavioral, and motion-rich widgets @@ -26,11 +29,3 @@ check out the [Material 3 demo][] web app. [Material 3]: https://m3.material.io/get-started [Migrate to Material 3]: /release/breaking-changes/material-3-migration [Material 3 demo]: {{site.github}}/flutter/samples/tree/main/material_3_demo/ - -{% render docs/catalog-page-material.md, categoryName:"Material components", catalog:catalog %} - -Find more widgets in the [Material 2 widget catalog][] -and other categories of the [widget catalog][]. - -[Material 2 widget catalog]: /ui/widgets/material2 -[widget catalog]: /ui/widgets diff --git a/src/content/ui/widgets/material2.md b/src/content/ui/widgets/material2.md index 0ca3a67bde3..c49b8f284be 100644 --- a/src/content/ui/widgets/material2.md +++ b/src/content/ui/widgets/material2.md @@ -1,8 +1,10 @@ --- title: Material 2 component widgets shortTitle: Material 2 -description: > +description: > A catalog of Flutter's widgets implementing the Material 2 design guidelines. +widgetCategory: Material 2 components +layout: widget-catalog-page --- Flutter provides a variety of widgets @@ -24,5 +26,3 @@ Also check out the [Material 3 widget catalog][]. [Material 2]: https://m2.material.io/design [Migrate to Material 3]: /release/breaking-changes/material-3-migration [Material 3 widget catalog]: /ui/widgets/material - -{% render docs/catalog-page.md, categoryName:"Material 2 components", catalog:catalog %} diff --git a/src/content/ui/widgets/painting.md b/src/content/ui/widgets/painting.md index 2a3bd606d3f..194ce85bf6d 100644 --- a/src/content/ui/widgets/painting.md +++ b/src/content/ui/widgets/painting.md @@ -3,6 +3,6 @@ title: Painting and effect widgets shortTitle: Painting description: > A catalog of Flutter's widgets that provide effects and custom painting. +widgetCategory: Painting and effects +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Painting and effects", catalog:catalog %} diff --git a/src/content/ui/widgets/scrolling.md b/src/content/ui/widgets/scrolling.md index 6921cb8dd9a..5095c412251 100644 --- a/src/content/ui/widgets/scrolling.md +++ b/src/content/ui/widgets/scrolling.md @@ -2,6 +2,6 @@ title: Scrolling widgets shortTitle: Scrolling description: A catalog of Flutter's widgets that enable or support scrolling. +widgetCategory: Scrolling +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Scrolling", catalog:catalog %} diff --git a/src/content/ui/widgets/styling.md b/src/content/ui/widgets/styling.md index 1e44523a1ac..68a7e562c43 100644 --- a/src/content/ui/widgets/styling.md +++ b/src/content/ui/widgets/styling.md @@ -2,6 +2,6 @@ title: Styling widgets shortTitle: Styling description: A catalog of Flutter's theming and responsiveness widgets. +widgetCategory: Styling +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Styling", catalog:catalog %} diff --git a/src/content/ui/widgets/text.md b/src/content/ui/widgets/text.md index 0a44de85e15..69bb08176a7 100644 --- a/src/content/ui/widgets/text.md +++ b/src/content/ui/widgets/text.md @@ -2,6 +2,6 @@ title: Text widgets shortTitle: Text description: A catalog of Flutter's widgets for displaying and styling text. +widgetCategory: Text +layout: widget-catalog-page --- - -{% render docs/catalog-page.md, categoryName:"Text", catalog:catalog %} diff --git a/src/_data/architectureRecommendations.yml b/src/data/architectureRecommendations.yml similarity index 100% rename from src/_data/architectureRecommendations.yml rename to src/data/architectureRecommendations.yml diff --git a/src/data/banner.yml b/src/data/banner.yml new file mode 100644 index 00000000000..84604e38cbc --- /dev/null +++ b/src/data/banner.yml @@ -0,0 +1,7 @@ +text: >- + Build high quality, feature-rich apps with + the new Flutter Extension for Gemini CLI. +link: + text: "Learn more" + url: "https://blog.flutter.dev/meet-the-flutter-extension-for-gemini-cli-f8be3643eaad" + newTab: true diff --git a/src/_data/catalog/index.yml b/src/data/catalog/index.yml similarity index 100% rename from src/_data/catalog/index.yml rename to src/data/catalog/index.yml diff --git a/src/_data/catalog/widgets.yml b/src/data/catalog/widgets.yml similarity index 100% rename from src/_data/catalog/widgets.yml rename to src/data/catalog/widgets.yml diff --git a/src/_data/docsCards.yml b/src/data/docsCards.yml similarity index 100% rename from src/_data/docsCards.yml rename to src/data/docsCards.yml diff --git a/src/_data/learning-resources-index/codelabs.yml b/src/data/learning-resources-index/codelabs.yml similarity index 99% rename from src/_data/learning-resources-index/codelabs.yml rename to src/data/learning-resources-index/codelabs.yml index 4fa7114a50b..e992280934d 100644 --- a/src/_data/learning-resources-index/codelabs.yml +++ b/src/data/learning-resources-index/codelabs.yml @@ -435,4 +435,4 @@ type: codelab link: label: Google Codelab - url: https://codelabs.developers.google.com/codelabs/flutter-github-client \ No newline at end of file + url: https://codelabs.developers.google.com/codelabs/flutter-github-client diff --git a/src/_data/learning-resources-index/cookbook.yml b/src/data/learning-resources-index/cookbook.yml similarity index 100% rename from src/_data/learning-resources-index/cookbook.yml rename to src/data/learning-resources-index/cookbook.yml diff --git a/src/_data/learning-resources-index/demos.yml b/src/data/learning-resources-index/demos.yml similarity index 90% rename from src/_data/learning-resources-index/demos.yml rename to src/data/learning-resources-index/demos.yml index c6e3f823be1..dfc9d47f083 100644 --- a/src/_data/learning-resources-index/demos.yml +++ b/src/data/learning-resources-index/demos.yml @@ -8,7 +8,7 @@ type: demo link: url: https://github.com/flutter/samples/tree/main/add_to_app - label: Flutter Github + label: Flutter GitHub - name: Android splash screen description: >- @@ -19,7 +19,7 @@ type: demo link: url: https://github.com/flutter/samples/tree/main/android_splash_screen - label: Flutter Github + label: Flutter GitHub - name: iOS app clip description: >- @@ -29,7 +29,7 @@ type: demo link: url: https://github.com/flutter/samples/tree/main/ios_app_clip - label: Flutter Github + label: Flutter GitHub - name: Swift platform view description: >- @@ -41,7 +41,7 @@ type: demo link: url: https://github.com/flutter/samples/tree/main/platform_view_swift - label: Flutter Github + label: Flutter GitHub - name: Simplistic editor description: >- @@ -52,4 +52,4 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/simplistic_editor - label: Flutter Github + label: Flutter GitHub diff --git a/src/_data/learning-resources-index/quickstarts_dart.yml b/src/data/learning-resources-index/quickstarts_dart.yml similarity index 91% rename from src/_data/learning-resources-index/quickstarts_dart.yml rename to src/data/learning-resources-index/quickstarts_dart.yml index 60d60134527..258906fe5da 100644 --- a/src/_data/learning-resources-index/quickstarts_dart.yml +++ b/src/data/learning-resources-index/quickstarts_dart.yml @@ -7,7 +7,7 @@ type: quickstart link: url: https://github.com/dart-lang/samples/tree/main/command_line - label: Dart Github + label: Dart GitHub - name: Extension methods description: >- @@ -18,7 +18,7 @@ type: quickstart link: url: https://github.com/dart-lang/samples/tree/main/extension_methods - label: Dart Github + label: Dart GitHub - name: FFI description: >- @@ -29,7 +29,7 @@ type: quickstart link: url: https://github.com/dart-lang/samples/tree/main/ffi - label: Dart Github + label: Dart GitHub - name: Isolates (in a CLI) description: >- @@ -41,7 +41,7 @@ type: quickstart link: url: https://github.com/dart-lang/samples/tree/main/ffi - label: Dart Github + label: Dart GitHub - name: Native Dart app description: >- @@ -53,7 +53,7 @@ type: quickstart link: url: https://github.com/dart-lang/samples/tree/main/native_app - label: Dart Github + label: Dart GitHub - name: Server side Dart description: >- @@ -64,7 +64,7 @@ type: quickstart link: url: https://github.com/dart-lang/samples/tree/main/server - label: Dart Github + label: Dart GitHub - name: Package constraint solver description: >- @@ -75,4 +75,4 @@ type: quickstart link: url: https://github.com/dart-lang/samples/tree/main/server - label: Dart Github \ No newline at end of file + label: Dart GitHub diff --git a/src/_data/learning-resources-index/quickstarts_flutter.yml b/src/data/learning-resources-index/quickstarts_flutter.yml similarity index 91% rename from src/_data/learning-resources-index/quickstarts_flutter.yml rename to src/data/learning-resources-index/quickstarts_flutter.yml index 802aa42efe4..774ed0f9c9b 100644 --- a/src/_data/learning-resources-index/quickstarts_flutter.yml +++ b/src/data/learning-resources-index/quickstarts_flutter.yml @@ -7,7 +7,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/asset_transformation - label: Flutter Github + label: Flutter GitHub - name: Background isolate channels description: >- @@ -17,7 +17,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/background_isolate_channels - label: Flutter Github + label: Flutter GitHub - name: Code sharing description: >- @@ -28,7 +28,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/code_sharing - label: Flutter Github + label: Flutter GitHub - name: Context menus description: >- @@ -41,7 +41,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/context_menus - label: Flutter Github + label: Flutter GitHub - name: Desktop UI description: >- @@ -53,7 +53,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/desktop_photo_search - label: Flutter Github + label: Flutter GitHub - name: AI generated dynamic theme description: >- @@ -65,7 +65,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/dynamic_theme - label: Flutter Github + label: Flutter GitHub - name: Form app description: >- @@ -76,7 +76,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/form_app - label: Flutter Github + label: Flutter GitHub - name: AI todo list description: >- @@ -88,7 +88,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/gemini_tasks - label: Flutter Github + label: Flutter GitHub - name: Google Maps plugin description: >- @@ -99,7 +99,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/google_maps - label: Flutter Github + label: Flutter GitHub - name: Infinite list description: >- @@ -112,7 +112,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/infinite_list - label: Flutter Github + label: Flutter GitHub - name: Isolates description: >- @@ -125,7 +125,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/isolate_example - label: Flutter Github + label: Flutter GitHub - name: Navigation and routing description: >- @@ -137,7 +137,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/navigation_and_routing - label: Flutter Github + label: Flutter GitHub - name: Google Maps Flutter plugin description: >- @@ -149,7 +149,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/place_tracker - label: Flutter Github + label: Flutter GitHub - name: Platform adaptive design description: >- @@ -162,7 +162,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/platform_design - label: Flutter Github + label: Flutter GitHub - name: Counter app with Provider description: >- @@ -174,7 +174,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/provider_counter - label: Flutter Github + label: Flutter GitHub - name: Shopping app with Provider description: >- @@ -186,7 +186,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/provider_shopper - label: Flutter Github + label: Flutter GitHub - name: Simple shaders description: >- @@ -197,7 +197,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/simple_shader - label: Flutter Github + label: Flutter GitHub - name: Desktop calculator description: >- @@ -207,7 +207,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/simplistic_calculator - label: Flutter Github + label: Flutter GitHub - name: Testing app description: >- @@ -217,7 +217,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/testing_app - label: Flutter Github + label: Flutter GitHub - name: Web element embedding description: >- @@ -229,7 +229,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/web_embedding/element_embedding_demo - label: Flutter Github + label: Flutter GitHub - name: ng-flutter description: >- @@ -241,7 +241,7 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/web_embedding/ng-flutter - label: Flutter Github + label: Flutter GitHub - name: Platform channels description: >- @@ -254,4 +254,4 @@ type: quickstart link: url: https://github.com/flutter/samples/tree/main/platform_channels - label: Flutter Github + label: Flutter GitHub diff --git a/src/_data/mirrors.yml b/src/data/mirrors.yml similarity index 100% rename from src/_data/mirrors.yml rename to src/data/mirrors.yml diff --git a/src/_data/platforms.yml b/src/data/platforms.yml similarity index 100% rename from src/_data/platforms.yml rename to src/data/platforms.yml diff --git a/src/_data/sidenav.yml b/src/data/sidenav.yml similarity index 99% rename from src/_data/sidenav.yml rename to src/data/sidenav.yml index 413d3f19bf0..083a6cad540 100644 --- a/src/_data/sidenav.yml +++ b/src/data/sidenav.yml @@ -5,6 +5,8 @@ permalink: /get-started hiddenChildren: true children: + - title: Overview + permalink: /get-started - title: Quick start permalink: /get-started/quick - title: Custom setup diff --git a/src/_data/site.yml b/src/data/site.yml similarity index 86% rename from src/_data/site.yml rename to src/data/site.yml index f3196167507..4ec48d350b4 100644 --- a/src/_data/site.yml +++ b/src/data/site.yml @@ -3,11 +3,6 @@ url: https://docs.flutter.dev main-url: https://flutter.dev email: flutter-dev@googlegroups.com -google_analytics_id: UA-67589403-1 -google_site_verification: HFqxhSbf9YA_0rBglNLzDiWnrHiK_w4cqDh2YD2GEY4 -google_tag_manager_id: GTM-ND4LWWZ -defaultShareImage: /assets/images/flutter-logo-sharing.png - showBanner: true branch: main @@ -24,8 +19,6 @@ repo: wonderous: https://github.com/gskinnerTeam/flutter-wonderous-app dart: api: https://api.dart.dev -sdk: - channel: stable # When changing this value also update it in src/_assets/js/archive.js social: twitter: https://twitter.com/FlutterDev youtube: https://www.youtube.com/@flutterdev @@ -60,3 +53,9 @@ yt: playlist: 'https://www.youtube.com/playlist?list=' currentFlutterVersion: '3.35.5' + +# Settings for Jaspr. + +# Specify Jaspr as not setting a base href for each document, +# so that links to fragments still work as expected. +base: false diff --git a/tool/flutter_site/analysis_options.yaml b/tool/dash_site/analysis_options.yaml similarity index 100% rename from tool/flutter_site/analysis_options.yaml rename to tool/dash_site/analysis_options.yaml diff --git a/tool/flutter_site/bin/flutter_site.dart b/tool/dash_site/bin/dash_site.dart similarity index 83% rename from tool/flutter_site/bin/flutter_site.dart rename to tool/dash_site/bin/dash_site.dart index c3253561dd0..bc68dc87f62 100644 --- a/tool/flutter_site/bin/flutter_site.dart +++ b/tool/dash_site/bin/dash_site.dart @@ -5,17 +5,17 @@ import 'dart:io'; import 'package:args/command_runner.dart'; -import 'package:flutter_site/flutter_site.dart'; +import 'package:dash_site/dash_site.dart'; import 'package:io/io.dart' as io; import 'package:path/path.dart' as path; void main(List args) async { // Verify that we are running from the root of the website repository. - if (!Directory(path.join('tool', 'flutter_site')).existsSync()) { + if (!Directory(path.join('tool', 'dash_site')).existsSync()) { throw Exception('Error: Wrong directory, run from root of the repository.'); } - final runner = FlutterSiteCommandRunner(); + final runner = DashSiteCommandRunner(); try { final result = await runner .run(args) diff --git a/tool/flutter_site/lib/flutter_site.dart b/tool/dash_site/lib/dash_site.dart similarity index 83% rename from tool/flutter_site/lib/flutter_site.dart rename to tool/dash_site/lib/dash_site.dart index 17cf1e96d0e..b5ba78e41b8 100644 --- a/tool/flutter_site/lib/flutter_site.dart +++ b/tool/dash_site/lib/dash_site.dart @@ -16,13 +16,14 @@ import 'src/commands/serve.dart'; import 'src/commands/test_dart.dart'; import 'src/commands/verify_firebase_json.dart'; -/// The root command runner of the `flutter_site` command. +/// The root command runner of the Fluter documentation website tooling. +/// /// To learn about it and its subcommands, -/// run `dart run flutter_site --help`. -final class FlutterSiteCommandRunner extends CommandRunner { - FlutterSiteCommandRunner() +/// run `dart run dash_site --help`. +final class DashSiteCommandRunner extends CommandRunner { + DashSiteCommandRunner() : super( - 'flutter_site', + 'dart run dash_site', 'Infrastructure tooling for the Flutter documentation website.', ) { addCommand(AnalyzeDartCommand()); diff --git a/tool/flutter_site/lib/src/commands/analyze_dart.dart b/tool/dash_site/lib/src/commands/analyze_dart.dart similarity index 97% rename from tool/flutter_site/lib/src/commands/analyze_dart.dart rename to tool/dash_site/lib/src/commands/analyze_dart.dart index e23f6a11642..af942ad03e6 100644 --- a/tool/flutter_site/lib/src/commands/analyze_dart.dart +++ b/tool/dash_site/lib/src/commands/analyze_dart.dart @@ -33,7 +33,8 @@ final class AnalyzeDartCommand extends Command { int analyzeDart({bool verboseLogging = false}) { final directoriesToAnalyze = [ - path.join('tool', 'flutter_site'), + path.join('site'), + path.join('tool', 'dash_site'), path.join('examples'), ]; diff --git a/tool/dash_site/lib/src/commands/build.dart b/tool/dash_site/lib/src/commands/build.dart new file mode 100644 index 00000000000..e59f921db49 --- /dev/null +++ b/tool/dash_site/lib/src/commands/build.dart @@ -0,0 +1,91 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:io/io.dart' as io; +import 'package:path/path.dart' as path; + +import '../utils.dart'; + +final class BuildSiteCommand extends Command { + static const String _releaseFlag = 'release'; + + BuildSiteCommand() { + argParser.addFlag( + _releaseFlag, + defaultsTo: false, + help: + 'Build a release build for docs.flutter.dev. ' + 'Optimizes site resources.', + ); + } + + @override + String get description => 'Build the site.'; + + @override + String get name => 'build'; + + @override + Future run() async { + installJasprCliIfNecessary(); + + final productionRelease = argResults.get(_releaseFlag, false); + + final process = await Process.start( + Platform.resolvedExecutable, + [ + 'pub', + 'global', + 'run', + 'jaspr_cli:jaspr', + 'build', + // Use build_web_compiler options specified in build.yaml instead of + // those specified by jaspr_cli. + '--no-managed-build-options', + '--sitemap-domain=https://docs.flutter.dev', + '--dart-define=PRODUCTION=$productionRelease', + ], + workingDirectory: 'site', + mode: ProcessStartMode.inheritStdio, + ); + + final processExitCode = await process.exitCode; + + final originalOutputDirectoryPath = path.join( + repositoryRoot, + 'site', + 'build', + 'jaspr', + ); + if (!Directory(originalOutputDirectoryPath).existsSync()) { + stderr.writeln( + 'Error: Jaspr output directory not found at: ' + '$originalOutputDirectoryPath', + ); + return 1; + } + + // Copy the entire site output to the _site directory. + io.copyPathSync(originalOutputDirectoryPath, siteOutputDirectoryPath); + + _move404File(); + + return processExitCode; + } +} + +/// Moves the 404 file to the location expected by Firebase hosting. +void _move404File() { + final initial404Directory = path.join(siteOutputDirectoryPath, '404'); + final original404File = File(path.join(initial404Directory, 'index.html')); + if (original404File.existsSync()) { + // If the 404 is in its own directory, + // copy the 404.html file to the root of the output directory. + original404File.copySync(path.join(siteOutputDirectoryPath, '404.html')); + Directory(initial404Directory).deleteSync(recursive: true); + } +} diff --git a/tool/flutter_site/lib/src/commands/check_all.dart b/tool/dash_site/lib/src/commands/check_all.dart similarity index 98% rename from tool/flutter_site/lib/src/commands/check_all.dart rename to tool/dash_site/lib/src/commands/check_all.dart index c0af2cebc54..cbb27aabf5d 100644 --- a/tool/flutter_site/lib/src/commands/check_all.dart +++ b/tool/dash_site/lib/src/commands/check_all.dart @@ -31,7 +31,7 @@ final class CheckAllCommand extends Command { groupStart(task.first); final process = await Process.start(Platform.resolvedExecutable, [ 'run', - 'flutter_site', + 'dash_site', ...task, ]); await stdout.addStream(process.stdout); diff --git a/tool/flutter_site/lib/src/commands/check_link_references.dart b/tool/dash_site/lib/src/commands/check_link_references.dart similarity index 100% rename from tool/flutter_site/lib/src/commands/check_link_references.dart rename to tool/dash_site/lib/src/commands/check_link_references.dart diff --git a/tool/flutter_site/lib/src/commands/check_links.dart b/tool/dash_site/lib/src/commands/check_links.dart similarity index 99% rename from tool/flutter_site/lib/src/commands/check_links.dart rename to tool/dash_site/lib/src/commands/check_links.dart index 70e604791e1..935031574ec 100644 --- a/tool/flutter_site/lib/src/commands/check_links.dart +++ b/tool/dash_site/lib/src/commands/check_links.dart @@ -37,7 +37,7 @@ final class CheckLinksCommand extends Command { /// The port that the firebase emulator runs on by default. /// This must match what's declared in the `firebase.json` /// and can't be 5000, since Airplay uses it. -const int _emulatorPort = 5500; +const int _emulatorPort = 5502; /// The path from root where the linkcheck skip list lives. final String _skipFilePath = path.join( diff --git a/tool/flutter_site/lib/src/commands/clean.dart b/tool/dash_site/lib/src/commands/clean.dart similarity index 64% rename from tool/flutter_site/lib/src/commands/clean.dart rename to tool/dash_site/lib/src/commands/clean.dart index aa99f6e69b3..29cfb4ed845 100644 --- a/tool/flutter_site/lib/src/commands/clean.dart +++ b/tool/dash_site/lib/src/commands/clean.dart @@ -19,12 +19,25 @@ final class CleanSiteCommand extends Command { @override Future run() async { + print('Cleaning the Jaspr setup...'); + + installJasprCliIfNecessary(); + + final process = await Process.start( + Platform.resolvedExecutable, + ['pub', 'global', 'run', 'jaspr_cli:jaspr', 'clean', '--kill'], + workingDirectory: 'site', + mode: ProcessStartMode.inheritStdio, + ); + + final processExitCode = await process.exitCode; + print('Cleaning the site output directory...'); final outputDirectory = Directory(siteOutputDirectoryPath); if (outputDirectory.existsSync()) { outputDirectory.deleteSync(recursive: true); } - return 0; + return processExitCode; } } diff --git a/tool/flutter_site/lib/src/commands/format_dart.dart b/tool/dash_site/lib/src/commands/format_dart.dart similarity index 99% rename from tool/flutter_site/lib/src/commands/format_dart.dart rename to tool/dash_site/lib/src/commands/format_dart.dart index 25e07195b87..468d7ff0664 100644 --- a/tool/flutter_site/lib/src/commands/format_dart.dart +++ b/tool/dash_site/lib/src/commands/format_dart.dart @@ -37,6 +37,7 @@ int formatDart({bool justCheck = false}) { // Currently format all Dart files in the /tool directory // and everything in /examples. final directoriesToFormat = [ + 'site', 'tool', ...Directory('examples') .listSync() diff --git a/tool/flutter_site/lib/src/commands/refresh_excerpts.dart b/tool/dash_site/lib/src/commands/refresh_excerpts.dart similarity index 97% rename from tool/flutter_site/lib/src/commands/refresh_excerpts.dart rename to tool/dash_site/lib/src/commands/refresh_excerpts.dart index ea2ca902c94..9c856fdcf84 100644 --- a/tool/flutter_site/lib/src/commands/refresh_excerpts.dart +++ b/tool/dash_site/lib/src/commands/refresh_excerpts.dart @@ -101,7 +101,7 @@ Future _refreshExcerpts({ return 1; } else if (failOnUpdate && updateResult.excerptsNeedingUpdates > 0) { stderr.writeln('Error: Some code excerpts needed to be updated!'); - stderr.writeln(' Run `./dash_site refresh-excerpts` to update.'); + stderr.writeln(' Run `dart run dash_site refresh-excerpts` to update.'); return 1; } diff --git a/tool/flutter_site/lib/src/commands/serve.dart b/tool/dash_site/lib/src/commands/serve.dart similarity index 57% rename from tool/flutter_site/lib/src/commands/serve.dart rename to tool/dash_site/lib/src/commands/serve.dart index bfe2be6aaa6..7fa2af3ac23 100644 --- a/tool/flutter_site/lib/src/commands/serve.dart +++ b/tool/dash_site/lib/src/commands/serve.dart @@ -9,38 +9,41 @@ import 'package:args/command_runner.dart'; import '../utils.dart'; final class ServeSiteCommand extends Command { - static const String _verboseFlag = 'verbose'; + @override + String get description => 'Serve the site locally.'; + + @override + String get name => 'serve'; ServeSiteCommand() { argParser.addFlag( - _verboseFlag, + 'release', defaultsTo: false, - help: 'Show verbose logging.', + help: 'Build with compilers used for release builds instead of dartdevc.', ); } - @override - String get description => 'Serve the site locally.'; - - @override - String get name => 'serve'; - @override Future run() async { - print('Building and serving site. This might take awhile...'); + final release = argResults!.flag('release'); + + installJasprCliIfNecessary(); - final verbose = argResults.get(_verboseFlag, false); final process = await Process.start( - 'npx', + Platform.resolvedExecutable, [ - 'tsx', - 'node_modules/@11ty/eleventy/cmd.cjs', - '--config=eleventy.config.ts', - '--serve', - '--incremental', - '--port=${Platform.environment['PORT'] ?? 4000}', + 'pub', + 'global', + 'run', + 'jaspr_cli:jaspr', + 'serve', + // Use build_web_compiler options specified in build.yaml instead of + // those specified by jaspr_cli. + '--no-managed-build-options', + '--dart-define=PRODUCTION=false', + if (release) '--release', ], - environment: {'PRODUCTION': 'false', if (verbose) 'DEBUG': 'Eleventy*'}, + workingDirectory: 'site', runInShell: true, mode: ProcessStartMode.inheritStdio, ); diff --git a/tool/flutter_site/lib/src/commands/test_dart.dart b/tool/dash_site/lib/src/commands/test_dart.dart similarity index 98% rename from tool/flutter_site/lib/src/commands/test_dart.dart rename to tool/dash_site/lib/src/commands/test_dart.dart index 7b27c9ebb65..81f61d6cb19 100644 --- a/tool/flutter_site/lib/src/commands/test_dart.dart +++ b/tool/dash_site/lib/src/commands/test_dart.dart @@ -33,7 +33,7 @@ final class TestDartCommand extends Command { Future _testDart({bool verboseLogging = false}) async { final directoriesToTest = [ - path.join('tool', 'flutter_site'), + path.join('tool', 'dash_site'), ...exampleProjectDirectories, ]; diff --git a/tool/flutter_site/lib/src/commands/verify_firebase_json.dart b/tool/dash_site/lib/src/commands/verify_firebase_json.dart similarity index 100% rename from tool/flutter_site/lib/src/commands/verify_firebase_json.dart rename to tool/dash_site/lib/src/commands/verify_firebase_json.dart diff --git a/tool/flutter_site/lib/src/utils.dart b/tool/dash_site/lib/src/utils.dart similarity index 79% rename from tool/flutter_site/lib/src/utils.dart rename to tool/dash_site/lib/src/utils.dart index 3e8d0794e82..f3cb366ad64 100644 --- a/tool/flutter_site/lib/src/utils.dart +++ b/tool/dash_site/lib/src/utils.dart @@ -9,21 +9,46 @@ import 'package:args/args.dart'; import 'package:path/path.dart' as path; /// The root path of the website repository. -String get repositoryRoot { +final String repositoryRoot = () { final packageConfigPath = path.fromUri(Isolate.packageConfigSync); final maybeRoot = path.dirname(path.dirname(packageConfigPath)); - if (!File(path.join(maybeRoot, 'dash_site')).existsSync()) { - throw StateError('Try calling dash_site from the root directory.'); + + // As a quick confidence check, verify that the + // root directory contains the firebase.json file. + if (!File(path.join(maybeRoot, 'firebase.json')).existsSync()) { + throw StateError('Try running the tool from the root directory.'); } return maybeRoot; -} +}(); /// The path of the site output directory. final String siteOutputDirectoryPath = path.join(repositoryRoot, '_site'); final bool _runningInCi = Platform.environment['CI'] == 'true'; +int installJasprCliIfNecessary() { + final activateOutput = Process.runSync(Platform.executable, const [ + 'pub', + 'global', + 'activate', + 'jaspr_cli', + '^0.21.6', + ]); + + if (activateOutput.exitCode != 0) { + final normalOutput = activateOutput.stdout.toString(); + final errorOutput = activateOutput.stderr.toString(); + + stderr.write(normalOutput); + stderr.write(errorOutput); + stderr.writeln('Error: Installing jaspr_cli failed.'); + return 1; + } + + return 0; +} + void groupStart(String text) { if (_runningInCi) { print('::group::$text'); diff --git a/tool/flutter_site/pubspec.yaml b/tool/dash_site/pubspec.yaml similarity index 75% rename from tool/flutter_site/pubspec.yaml rename to tool/dash_site/pubspec.yaml index ebe29f7cc5a..2400a22ea65 100644 --- a/tool/flutter_site/pubspec.yaml +++ b/tool/dash_site/pubspec.yaml @@ -1,10 +1,10 @@ -name: flutter_site +name: dash_site description: Dart-based tools for building docs.flutter.dev. publish_to: none resolution: workspace environment: - sdk: ^3.9.0 + sdk: ^3.9.2 dependencies: args: ^2.7.0 @@ -12,7 +12,7 @@ dependencies: git: url: https://github.com/dart-lang/site-shared path: pkgs/excerpter - ref: 88aa84df953e67b7595b1e214b717f26d81ed538 + ref: f91ed8ecef6a0b31685804fe4102b25fda021460 io: ^1.0.5 linkcheck: ^3.1.0 path: ^1.9.1 @@ -22,4 +22,4 @@ dev_dependencies: git: url: https://github.com/dart-lang/site-shared path: pkgs/analysis_defaults - ref: 88aa84df953e67b7595b1e214b717f26d81ed538 + ref: f91ed8ecef6a0b31685804fe4102b25fda021460 diff --git a/tool/flutter_site/lib/src/commands/build.dart b/tool/flutter_site/lib/src/commands/build.dart deleted file mode 100644 index 02923397198..00000000000 --- a/tool/flutter_site/lib/src/commands/build.dart +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2024 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:io'; - -import 'package:args/command_runner.dart'; - -import '../utils.dart'; - -final class BuildSiteCommand extends Command { - static const String _releaseFlag = 'release'; - - BuildSiteCommand() { - argParser.addFlag( - _releaseFlag, - defaultsTo: false, - help: - 'Build a release build for docs.flutter.dev. ' - 'Optimizes site resources.', - ); - } - - @override - String get description => 'Build the site.'; - - @override - String get name => 'build'; - - @override - Future run() async { - print('Building site. This might take awhile...'); - - final productionRelease = argResults.get(_releaseFlag, false); - - final process = await Process.start( - 'npx', - const [ - 'tsx', - 'node_modules/@11ty/eleventy/cmd.cjs', - '--config=eleventy.config.ts', - ], - environment: { - 'PRODUCTION': '$productionRelease', - 'OPTIMIZE': '$productionRelease', - }, - ); - - await stdout.addStream(process.stdout); - await stderr.addStream(process.stderr); - - final processExitCode = await process.exitCode; - return processExitCode; - } -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index ceeac1f41c8..00000000000 --- a/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "module": "NodeNext", - "target": "ESNext", - "types": ["node", "markdown-it", "hast"], - "skipLibCheck": true, - "allowSyntheticDefaultImports": true - }, - "exclude": ["node_modules", "_site"] -}