Skip to content

Commit c2a55e5

Browse files
Update Handbook Structure (#2)
Co-authored-by: UltralyticsAssistant <[email protected]>
1 parent ece17e3 commit c2a55e5

File tree

10 files changed

+688
-17
lines changed

10 files changed

+688
-17
lines changed
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Ultralytics 🚀 - AGPL-3.0 License https://ultralytics.com/license
2+
3+
name: Publish Handbook to GitHub Pages
4+
5+
on:
6+
workflow_dispatch:
7+
push:
8+
branches:
9+
- main
10+
11+
jobs:
12+
deploy:
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: write
16+
steps:
17+
- uses: actions/checkout@v3
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v4
21+
with:
22+
python-version: '3.x'
23+
24+
- name: Cache dependencies
25+
uses: actions/cache@v3
26+
with:
27+
path: ~/.cache/pip
28+
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
29+
restore-keys: |
30+
${{ runner.os }}-pip-
31+
32+
- name: Install dependencies
33+
run: |
34+
python -m pip install --upgrade pip
35+
pip install black mkdocs-material mkdocs-ultralytics-plugin
36+
37+
- name: Build site
38+
run: mkdocs build
39+
40+
- name: Deploy to GitHub Pages
41+
run: |
42+
git config --global user.name 'UltralyticsAssistant'
43+
git config --global user.email '[email protected]'
44+
git fetch origin gh-pages
45+
git checkout --track origin/gh-pages || git checkout -b gh-pages
46+
git rm -rf .
47+
mv site/* .
48+
rm -rf site
49+
git add .
50+
git commit -m "Deploy handbook to GitHub Pages"
51+
git push origin gh-pages

.github/workflows/tag.yml

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Ultralytics 🚀 - AGPL-3.0 License https://ultralytics.com/license
2+
# Ultralytics Actions https://github.com/ultralytics/actions
3+
# This workflow automatically publishes a new repository tag and release
4+
5+
name: Tag and Release
6+
7+
on:
8+
workflow_dispatch:
9+
inputs:
10+
tag_name:
11+
description: 'Tag name (e.g., v0.0.0)'
12+
required: true
13+
type: string
14+
publish_tag:
15+
description: 'Publish new tag'
16+
required: true
17+
type: boolean
18+
default: true
19+
publish_release:
20+
description: 'Publish new release'
21+
required: true
22+
type: boolean
23+
default: true
24+
25+
jobs:
26+
tag-and-release:
27+
if: github.repository == 'ultralytics/docs' && github.actor == 'glenn-jocher'
28+
name: Tag and Release
29+
runs-on: ubuntu-latest
30+
steps:
31+
- name: Checkout code
32+
uses: actions/checkout@v4
33+
with:
34+
fetch-depth: 0
35+
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
36+
37+
- name: Git config
38+
run: |
39+
git config --global user.name "UltralyticsAssistant"
40+
git config --global user.email "[email protected]"
41+
42+
- name: Check if tag exists
43+
id: check_tag
44+
run: |
45+
if git rev-parse ${{ github.event.inputs.tag_name }} >/dev/null 2>&1; then
46+
echo "Tag ${{ github.event.inputs.tag_name }} already exists"
47+
echo "tag_exists=true" >> $GITHUB_OUTPUT
48+
else
49+
echo "Tag ${{ github.event.inputs.tag_name }} does not exist"
50+
echo "tag_exists=false" >> $GITHUB_OUTPUT
51+
fi
52+
53+
- name: Publish new tag
54+
if: steps.check_tag.outputs.tag_exists == 'false'
55+
run: |
56+
git tag -a "${{ github.event.inputs.tag_name }}" -m "$(git log -1 --pretty=%B)"
57+
git push origin "${{ github.event.inputs.tag_name }}"
58+
59+
- name: Set up Python environment
60+
uses: actions/setup-python@v5
61+
with:
62+
python-version: "3.x"
63+
64+
- name: Install dependencies
65+
run: |
66+
python -m pip install --upgrade pip wheel
67+
pip install requests
68+
69+
- name: Publish new release
70+
env:
71+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
72+
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
73+
CURRENT_TAG: ${{ github.event.inputs.tag_name }}
74+
run: |
75+
curl -s "https://raw.githubusercontent.com/ultralytics/actions/main/utils/summarize_release.py" | python -
76+
shell: bash

docs/mkdocs_github_authors.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
2+
avatar: https://avatars.githubusercontent.com/u/26833433?v=4
3+
username: glenn-jocher
14
not.committed.yet:
25
avatar: https://avatars.githubusercontent.com/u/135830346?v=4
36
username: UltralyticsAssistant
47
58
avatar: https://avatars.githubusercontent.com/u/135830346?v=4
69
username: UltralyticsAssistant
7-
8-
avatar: https://avatars.githubusercontent.com/u/26833433?v=4
9-
username: glenn-jocher

docs/overrides/assets/favicon.ico

9.44 KB
Binary file not shown.

docs/overrides/javascript/extra.js

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Function that applies light/dark theme based on the user's preference
2+
const applyAutoTheme = () => {
3+
// Determine the user's preferred color scheme
4+
const prefersLight = window.matchMedia("(prefers-color-scheme: light)").matches;
5+
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
6+
7+
// Apply the appropriate attributes based on the user's preference
8+
if (prefersLight) {
9+
document.body.setAttribute("data-md-color-scheme", "default");
10+
document.body.setAttribute("data-md-color-primary", "indigo");
11+
} else if (prefersDark) {
12+
document.body.setAttribute("data-md-color-scheme", "slate");
13+
document.body.setAttribute("data-md-color-primary", "black");
14+
}
15+
};
16+
17+
// Function that checks and applies light/dark theme based on the user's preference (if auto theme is enabled)
18+
function checkAutoTheme() {
19+
// Array of supported language codes -> each language has its own palette (stored in local storage)
20+
const supportedLangCodes = ["en", "zh", "ko", "ja", "ru", "de", "fr", "es", "pt", "it", "tr", "vi", "nl"];
21+
// Get the URL path
22+
const path = window.location.pathname;
23+
// Extract the language code from the URL (assuming it's in the format /xx/...)
24+
const langCode = path.split("/")[1];
25+
// Check if the extracted language code is in the supported languages
26+
const isValidLangCode = supportedLangCodes.includes(langCode);
27+
// Construct the local storage key based on the language code if valid, otherwise default to the root key
28+
const localStorageKey = isValidLangCode ? `/${langCode}/.__palette` : "/.__palette";
29+
// Retrieve the palette from local storage using the constructed key
30+
const palette = localStorage.getItem(localStorageKey);
31+
if (palette) {
32+
// Check if the palette's index is 0 (auto theme)
33+
const paletteObj = JSON.parse(palette);
34+
if (paletteObj && paletteObj.index === 0) {
35+
applyAutoTheme();
36+
}
37+
}
38+
}
39+
40+
// Run function when the script loads
41+
checkAutoTheme();
42+
43+
// Re-run the function when the user's preference changes (when the user changes their system theme)
44+
window.matchMedia("(prefers-color-scheme: light)").addEventListener("change", checkAutoTheme);
45+
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", checkAutoTheme);
46+
47+
// Re-run the function when the palette changes (e.g. user switched from dark theme to auto theme)
48+
// ! We can't use window.addEventListener("storage", checkAutoTheme) because it will NOT be triggered on the current tab
49+
// ! So we have to use the following workaround:
50+
// Get the palette input for auto theme
51+
var autoThemeInput = document.getElementById("__palette_1");
52+
if (autoThemeInput) {
53+
// Add a click event listener to the input
54+
autoThemeInput.addEventListener("click", function () {
55+
// Check if the auto theme is selected
56+
if (autoThemeInput.checked) {
57+
// Re-run the function after a short delay (to ensure that the palette has been updated)
58+
setTimeout(applyAutoTheme);
59+
}
60+
});
61+
}
62+
63+
// Add iframe navigation
64+
window.onhashchange = function() {
65+
window.parent.postMessage({
66+
type: 'navigation',
67+
hash: window.location.pathname + window.location.search + window.location.hash
68+
}, '*');
69+
};
70+
71+
// Add Inkeep button
72+
document.addEventListener("DOMContentLoaded", () => {
73+
const inkeepScript = document.createElement("script");
74+
inkeepScript.src = "https://unpkg.com/@inkeep/[email protected]/dist/embed.js";
75+
inkeepScript.type = "module";
76+
inkeepScript.defer = true;
77+
document.head.appendChild(inkeepScript);
78+
79+
// Configure and initialize the widget
80+
const addInkeepWidget = () => {
81+
const inkeepWidget = Inkeep().embed({
82+
componentType: "ChatButton",
83+
colorModeSync: {
84+
observedElement: document.documentElement,
85+
isDarkModeCallback: (el) => {
86+
const currentTheme = el.getAttribute("data-color-mode");
87+
return currentTheme === "dark";
88+
},
89+
colorModeAttribute: "data-color-mode",
90+
},
91+
properties: {
92+
chatButtonType: "PILL",
93+
fixedPositionXOffset: "1rem",
94+
fixedPositionYOffset: "3rem",
95+
chatButtonBgColor: "#E1FF25",
96+
baseSettings: {
97+
apiKey: "13dfec2e75982bc9bae3199a08e13b86b5fbacd64e9b2f89",
98+
integrationId: "cm1shscmm00y26sj83lgxzvkw",
99+
organizationId: "org_e3869az6hQZ0mXdF",
100+
primaryBrandColor: "#E1FF25",
101+
organizationDisplayName: "Ultralytics",
102+
theme: {
103+
stylesheetUrls: ["/stylesheets/style.css"],
104+
},
105+
// ...optional settings
106+
},
107+
modalSettings: {
108+
// optional settings
109+
},
110+
searchSettings: {
111+
// optional settings
112+
},
113+
aiChatSettings: {
114+
chatSubjectName: "Ultralytics",
115+
botAvatarSrcUrl: "https://storage.googleapis.com/organization-image-assets/ultralytics-botAvatarSrcUrl-1727908259285.png",
116+
botAvatarDarkSrcUrl: "https://storage.googleapis.com/organization-image-assets/ultralytics-botAvatarDarkSrcUrl-1727908258478.png",
117+
quickQuestions: [
118+
"What's new in Ultralytics YOLO11?",
119+
"How can I get started with Ultralytics HUB?",
120+
"How does Ultralytics Enterprise Licensing work?"
121+
],
122+
getHelpCallToActions: [
123+
{
124+
name: "Ask on Ultralytics GitHub",
125+
url: "https://github.com/ultralytics/ultralytics",
126+
icon: {
127+
builtIn: "FaGithub"
128+
}
129+
},
130+
{
131+
name: "Ask on Ultralytics Discourse",
132+
url: "https://community.ultralytics.com/",
133+
icon: {
134+
builtIn: "FaDiscourse"
135+
}
136+
},
137+
{
138+
name: "Ask on Ultralytics Discord",
139+
url: "https://discord.com/invite/ultralytics",
140+
icon: {
141+
builtIn: "FaDiscord"
142+
}
143+
}
144+
],
145+
},
146+
},
147+
});
148+
};
149+
inkeepScript.addEventListener("load", () => {
150+
addInkeepWidget(); // initialize the widget
151+
});
152+
});

docs/overrides/main.html

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!--Ultralytics YOLO 🚀, AGPL-3.0 license-->
2+
3+
{% extends "base.html" %} {% block announce %}
4+
<div class="banner-wrapper">
5+
<div class="banner-content-wrapper">
6+
<p>YOLO Vision 2024 is here!</p>
7+
<div class="banner-info-wrapper">
8+
<img
9+
src="https://assets-global.website-files.com/646dd1f1a3703e451ba81ecc/66e9a87cfc78245ffa51d6f0_w_yv24.svg"
10+
loading="lazy"
11+
width="20"
12+
height="20"
13+
alt="YOLO Vision 24"
14+
/>
15+
<p>September 27, 2024</p>
16+
</div>
17+
<div class="banner-info-wrapper">
18+
<img
19+
src="https://assets-global.website-files.com/646dd1f1a3703e451ba81ecc/66e9a87cdfbd25e409560ed8_l_yv24.svg"
20+
loading="lazy"
21+
width="20"
22+
height="20"
23+
alt="YOLO Vision 24"
24+
/>
25+
<p>Free hybrid event</p>
26+
</div>
27+
</div>
28+
<div class="banner-button-wrapper">
29+
<div class="banner-button-wrapper large">
30+
<button
31+
onclick="window.open('https://www.ultralytics.com/events/yolovision', '_blank')"
32+
>
33+
Register now
34+
</button>
35+
</div>
36+
</div>
37+
</div>
38+
{% endblock %}

docs/overrides/partials/comments.html

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{% if page.meta.comments %}
2+
<h2 id="__comments">{{ lang.t("meta.comments") }}</h2>
3+
4+
<!-- Insert Giscus code snippet from https://giscus.app/ here -->
5+
<script async
6+
crossorigin="anonymous"
7+
data-category="Docs"
8+
data-category-id="DIC_kwDOH-jzvc4CWLkL"
9+
data-emit-metadata="0"
10+
data-input-position="top"
11+
data-lang="en"
12+
data-loading="lazy"
13+
data-mapping="pathname"
14+
data-reactions-enabled="1"
15+
data-repo="ultralytics/ultralytics"
16+
data-repo-id="R_kgDOH-jzvQ"
17+
data-strict="1"
18+
data-theme="preferred_color_scheme"
19+
src="https://giscus.app/client.js">
20+
</script>
21+
22+
<!-- Synchronize Giscus theme with palette -->
23+
<script>
24+
var giscus = document.querySelector("script[src*=giscus]")
25+
26+
/* Set palette on initial load */
27+
var palette = __md_get("__palette")
28+
if (palette && typeof palette.color === "object") {
29+
var theme = palette.color.scheme === "slate" ? "dark" : "light"
30+
giscus.setAttribute("data-theme", theme)
31+
}
32+
33+
/* Register event handlers after documented loaded */
34+
document.addEventListener("DOMContentLoaded", function() {
35+
var ref = document.querySelector("[data-md-component=palette]")
36+
ref.addEventListener("change", function() {
37+
var palette = __md_get("__palette")
38+
if (palette && typeof palette.color === "object") {
39+
var theme = palette.color.scheme === "slate" ? "dark" : "light"
40+
41+
/* Instruct Giscus to change theme */
42+
var frame = document.querySelector(".giscus-frame")
43+
frame.contentWindow.postMessage(
44+
{ giscus: { setConfig: { theme } } },
45+
"https://giscus.app"
46+
)
47+
}
48+
})
49+
})
50+
</script>
51+
{% endif %}

0 commit comments

Comments
 (0)