]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
✨ Add Material for MkDocs Insiders features and cards (#9748)
authorSebastián Ramírez <tiangolo@gmail.com>
Mon, 26 Jun 2023 14:05:43 +0000 (16:05 +0200)
committerGitHub <noreply@github.com>
Mon, 26 Jun 2023 14:05:43 +0000 (16:05 +0200)
* ➕ Add dependencies for MkDocs Insiders

* 🙈 Add Insider's .cache to .gitignore

* 🔧 Update MkDocs configs for Insiders

* 💄 Add custom Insiders card layout, while the custom logo is provided from upstream

* 🔨 Update docs.py script to dynamically enable insiders if it's installed

* 👷 Add cache for MkDocs Material Insiders' cards

* 🔊 Add a small log to the docs CLI

* 🔊 Tweak logs, only after exporting languages

* 🐛 Fix accessing non existing env var

* 🔧 Invalidate deps cache

* 🔧 Tweak cache IDs

* 👷 Update cache for installing insiders

* 🔊 Log insiders

* 💚 Invalidate cache

* 👷 Tweak cache keys

* 👷 Trigger CI and test cache

* 🔥 Remove cache comment

* ⚡️ Optimize cache usage for first runs of docs

* 👷 Tweak cache for MkDocs Material cards

* 💚 Trigger CI to test cache

.github/workflows/build-docs.yml
.gitignore
docs/en/layouts/custom.yml [new file with mode: 0644]
docs/en/mkdocs.insiders.yml [new file with mode: 0644]
docs/en/mkdocs.maybe-insiders.yml [new file with mode: 0644]
docs/en/mkdocs.no-insiders.yml [new file with mode: 0644]
docs/en/mkdocs.yml
requirements-docs.txt
scripts/docs.py

index c2880ef711418ec0f08a4247e4a5085d2c11b43c..a155ecfeca6cce099947fcb9a86aa0860b87f9c4 100644 (file)
@@ -44,10 +44,14 @@ jobs:
         id: cache
         with:
           path: ${{ env.pythonLocation }}
-          key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v03
+          key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v05
       - name: Install docs extras
         if: steps.cache.outputs.cache-hit != 'true'
         run: pip install -r requirements-docs.txt
+      # Install MkDocs Material Insiders here just to put it in the cache for the rest of the steps
+      - name: Install Material for MkDocs Insiders
+        if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true'
+        run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
       - name: Export Language Codes
         id: show-langs
         run: |
@@ -76,7 +80,7 @@ jobs:
         id: cache
         with:
           path: ${{ env.pythonLocation }}
-          key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v03
+          key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v05
       - name: Install docs extras
         if: steps.cache.outputs.cache-hit != 'true'
         run: pip install -r requirements-docs.txt
@@ -85,6 +89,10 @@ jobs:
         run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
       - name: Update Languages
         run: python ./scripts/docs.py update-languages
+      - uses: actions/cache@v3
+        with:
+          key: mkdocs-cards-${{ matrix.lang }}-${{ github.ref }}
+          path: docs/${{ matrix.lang }}/.cache
       - name: Build Docs
         run: python ./scripts/docs.py build-lang ${{ matrix.lang }}
       - uses: actions/upload-artifact@v3
index 3cb64c0476f0f53b7db4ab350bfdf0decb073319..d380d16b7d7b3ca42957de1ed3b1a48849a29761 100644 (file)
@@ -24,3 +24,4 @@ archive.zip
 # vim temporary files
 *~
 .*.sw?
+.cache
diff --git a/docs/en/layouts/custom.yml b/docs/en/layouts/custom.yml
new file mode 100644 (file)
index 0000000..aad81af
--- /dev/null
@@ -0,0 +1,228 @@
+# Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com>
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+# -----------------------------------------------------------------------------
+# Configuration
+# -----------------------------------------------------------------------------
+
+# The same default card with a a configurable logo
+
+# Definitions
+definitions:
+
+  # Background image
+  - &background_image >-
+    {{ layout.background_image or "" }}
+
+  # Background color (default: indigo)
+  - &background_color >-
+    {%- if layout.background_color -%}
+      {{ layout.background_color }}
+    {%- else -%}
+      {%- set palette = config.theme.palette or {} -%}
+      {%- if not palette is mapping -%}
+        {%- set palette = palette | first -%}
+      {%- endif -%}
+      {%- set primary = palette.get("primary", "indigo") -%}
+      {%- set primary = primary.replace(" ", "-") -%}
+      {{ {
+        "red":         "#ef5552",
+        "pink":        "#e92063",
+        "purple":      "#ab47bd",
+        "deep-purple": "#7e56c2",
+        "indigo":      "#4051b5",
+        "blue":        "#2094f3",
+        "light-blue":  "#02a6f2",
+        "cyan":        "#00bdd6",
+        "teal":        "#009485",
+        "green":       "#4cae4f",
+        "light-green": "#8bc34b",
+        "lime":        "#cbdc38",
+        "yellow":      "#ffec3d",
+        "amber":       "#ffc105",
+        "orange":      "#ffa724",
+        "deep-orange": "#ff6e42",
+        "brown":       "#795649",
+        "grey":        "#757575",
+        "blue-grey":   "#546d78",
+        "black":       "#000000",
+        "white":       "#ffffff"
+      }[primary] or "#4051b5" }}
+    {%- endif -%}
+
+  # Text color (default: white)
+  - &color >-
+    {%- if layout.color -%}
+      {{ layout.color }}
+    {%- else -%}
+      {%- set palette = config.theme.palette or {} -%}
+      {%- if not palette is mapping -%}
+        {%- set palette = palette | first -%}
+      {%- endif -%}
+      {%- set primary = palette.get("primary", "indigo") -%}
+      {%- set primary = primary.replace(" ", "-") -%}
+      {{ {
+        "red":         "#ffffff",
+        "pink":        "#ffffff",
+        "purple":      "#ffffff",
+        "deep-purple": "#ffffff",
+        "indigo":      "#ffffff",
+        "blue":        "#ffffff",
+        "light-blue":  "#ffffff",
+        "cyan":        "#ffffff",
+        "teal":        "#ffffff",
+        "green":       "#ffffff",
+        "light-green": "#ffffff",
+        "lime":        "#000000",
+        "yellow":      "#000000",
+        "amber":       "#000000",
+        "orange":      "#000000",
+        "deep-orange": "#ffffff",
+        "brown":       "#ffffff",
+        "grey":        "#ffffff",
+        "blue-grey":   "#ffffff",
+        "black":       "#ffffff",
+        "white":       "#000000"
+      }[primary] or "#ffffff" }}
+    {%- endif -%}
+
+  # Font family (default: Roboto)
+  - &font_family >-
+    {%- if layout.font_family -%}
+      {{ layout.font_family }}
+    {%- elif config.theme.font != false -%}
+      {{ config.theme.font.get("text", "Roboto") }}
+    {%- else -%}
+      Roboto
+    {%- endif -%}
+
+  # Site name
+  - &site_name >-
+    {{ config.site_name }}
+
+  # Page title
+  - &page_title >-
+    {{ page.meta.get("title", page.title) }}
+
+  # Page title with site name
+  - &page_title_with_site_name >-
+    {%- if not page.is_homepage -%}
+      {{ page.meta.get("title", page.title) }} - {{ config.site_name }}
+    {%- else -%}
+      {{ page.meta.get("title", page.title) }}
+    {%- endif -%}
+
+  # Page description
+  - &page_description >-
+    {{ page.meta.get("description", config.site_description) or "" }}
+
+
+  # Start of custom modified logic
+  # Logo
+  - &logo >-
+    {%- if layout.logo -%}
+      {{ layout.logo }}
+    {%- elif config.theme.logo -%}
+      {{ config.docs_dir }}/{{ config.theme.logo }}
+    {%- endif -%}
+  # End of custom modified logic
+
+  # Logo (icon)
+  - &logo_icon >-
+    {{ config.theme.icon.logo or "" }}
+
+# Meta tags
+tags:
+
+  # Open Graph
+  og:type: website
+  og:title: *page_title_with_site_name
+  og:description: *page_description
+  og:image: "{{ image.url }}"
+  og:image:type: "{{ image.type }}"
+  og:image:width: "{{ image.width }}"
+  og:image:height: "{{ image.height }}"
+  og:url: "{{ page.canonical_url }}"
+
+  # Twitter
+  twitter:card: summary_large_image
+  twitter.title: *page_title_with_site_name
+  twitter:description: *page_description
+  twitter:image: "{{ image.url }}"
+
+# -----------------------------------------------------------------------------
+# Specification
+# -----------------------------------------------------------------------------
+
+# Card size and layers
+size: { width: 1200, height: 630 }
+layers:
+
+  # Background
+  - background:
+      image: *background_image
+      color: *background_color
+
+  # Logo
+  - size: { width: 144, height: 144 }
+    offset: { x: 992, y: 64 }
+    background:
+      image: *logo
+    icon:
+      value: *logo_icon
+      color: *color
+
+  # Site name
+  - size: { width: 832, height: 42 }
+    offset: { x: 64, y: 64 }
+    typography:
+      content: *site_name
+      color: *color
+      font:
+        family: *font_family
+        style: Bold
+
+  # Page title
+  - size: { width: 832, height: 310 }
+    offset: { x: 62, y: 160 }
+    typography:
+      content: *page_title
+      align: start
+      color: *color
+      line:
+        amount: 3
+        height: 1.25
+      font:
+        family: *font_family
+        style: Bold
+
+  # Page description
+  - size: { width: 832, height: 64 }
+    offset: { x: 64, y: 512 }
+    typography:
+      content: *page_description
+      align: start
+      color: *color
+      line:
+        amount: 2
+        height: 1.5
+      font:
+        family: *font_family
+        style: Regular
diff --git a/docs/en/mkdocs.insiders.yml b/docs/en/mkdocs.insiders.yml
new file mode 100644 (file)
index 0000000..d204974
--- /dev/null
@@ -0,0 +1,7 @@
+plugins:
+  social:
+    cards_layout_dir: ../en/layouts
+    cards_layout: custom
+    cards_layout_options:
+      logo: ../en/docs/img/icon-white.svg
+  typeset:
diff --git a/docs/en/mkdocs.maybe-insiders.yml b/docs/en/mkdocs.maybe-insiders.yml
new file mode 100644 (file)
index 0000000..8e62713
--- /dev/null
@@ -0,0 +1,3 @@
+# Define this here and not in the main mkdocs.yml file because that one is auto
+# updated and written, and the script would remove the env var
+INHERIT: !ENV [INSIDERS_FILE, '../en/mkdocs.no-insiders.yml']
diff --git a/docs/en/mkdocs.no-insiders.yml b/docs/en/mkdocs.no-insiders.yml
new file mode 100644 (file)
index 0000000..e69de29
index c39d656ff0bd6051cef97b447631f508b512d142..bdadb167e6df12f2ac8c5ddf2ae7ea3f03975dd1 100644 (file)
@@ -1,3 +1,4 @@
+INHERIT: ../en/mkdocs.maybe-insiders.yml
 site_name: FastAPI
 site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
 site_url: https://fastapi.tiangolo.com/
@@ -24,6 +25,11 @@ theme:
   - search.highlight
   - content.tabs.link
   - navigation.indexes
+  - content.tooltips
+  - navigation.path
+  - content.code.annotate
+  - content.code.copy
+  - content.code.select
   icon:
     repo: fontawesome/brands/github-alt
   logo: img/icon-white.svg
@@ -33,8 +39,8 @@ repo_name: tiangolo/fastapi
 repo_url: https://github.com/tiangolo/fastapi
 edit_uri: ''
 plugins:
-- search
-- markdownextradata:
+  search: null
+  markdownextradata:
     data: ../en/data
 nav:
 - FastAPI: index.md
index 211212fba986c5843711712fd956af18cd57a01e..2c5f71ec04973ac106a9be15b134f607cdbef933 100644 (file)
@@ -6,3 +6,9 @@ mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0
 typer-cli >=0.0.13,<0.0.14
 typer[all] >=0.6.1,<0.8.0
 pyyaml >=5.3.1,<7.0.0
+# For Material for MkDocs, Chinese search
+jieba==0.42.1
+# For image processing by Material for MkDocs
+pillow==9.5.0
+# For image processing by Material for MkDocs
+cairosvg==2.7.0
index 5615a8572cf4e0d1edd9378eb65ac0f5255d6687..20838be6a716a17b75bd6a9a71c23de0cb4f7cdf 100644 (file)
@@ -4,7 +4,9 @@ import os
 import re
 import shutil
 import subprocess
+from functools import lru_cache
 from http.server import HTTPServer, SimpleHTTPRequestHandler
+from importlib import metadata
 from multiprocessing import Pool
 from pathlib import Path
 from typing import Any, Dict, List, Optional, Union
@@ -34,6 +36,12 @@ site_path = Path("site").absolute()
 build_site_path = Path("site_build").absolute()
 
 
+@lru_cache()
+def is_mkdocs_insiders() -> bool:
+    version = metadata.version("mkdocs-material")
+    return "insiders" in version
+
+
 def get_en_config() -> Dict[str, Any]:
     return mkdocs.utils.yaml_load(en_config_path.read_text(encoding="utf-8"))
 
@@ -59,6 +67,14 @@ def complete_existing_lang(incomplete: str):
             yield lang_path.name
 
 
+@app.callback()
+def callback() -> None:
+    if is_mkdocs_insiders():
+        os.environ["INSIDERS_FILE"] = "../en/mkdocs.insiders.yml"
+    # For MacOS with insiders and Cairo
+    os.environ["DYLD_FALLBACK_LIBRARY_PATH"] = "/opt/homebrew/lib"
+
+
 @app.command()
 def new_lang(lang: str = typer.Argument(..., callback=lang_callback)):
     """
@@ -93,6 +109,10 @@ def build_lang(
     """
     Build the docs for a language.
     """
+    insiders_env_file = os.environ.get("INSIDERS_FILE")
+    print(f"Insiders file {insiders_env_file}")
+    if is_mkdocs_insiders():
+        print("Using insiders")
     lang_path: Path = Path("docs") / lang
     if not lang_path.is_dir():
         typer.echo(f"The language translation doesn't seem to exist yet: {lang}")