Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(theme): add versions attribute to docsVersionDropdown navbar item #10852

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
544045f
feat(theme-classic): implemented version configurations for "docsVers…
hrumhurum Jan 18, 2025
36a35e5
docs(theme-classic): added docs for versions configuration of "docsVe…
hrumhurum Jan 18, 2025
5e8032b
feat(theme-classic): preserve order of version configurations in "doc…
hrumhurum Jan 18, 2025
0a02b47
docs(theme-classic): fixed docs formatting issue for versions configu…
hrumhurum Jan 18, 2025
c791a47
docs(theme-classic): improved wording in docs for versions configurat…
hrumhurum Jan 18, 2025
8e21202
docs(theme-classic): more precise docs for versions configuration of …
hrumhurum Jan 18, 2025
fd8f2db
docs(theme-classic): fixed anchor for versions configuration docs of …
hrumhurum Jan 19, 2025
10976ad
docs(theme-classic): simplified example code for versions configurati…
hrumhurum Jan 19, 2025
bcae6cb
feat(theme-classic): use formal version identifiers for version confi…
hrumhurum Jan 19, 2025
9e166c3
feat(theme-classic): implementation refactoring of version configurat…
hrumhurum Jan 19, 2025
a5afe09
feat(theme-classic): version configurations in "docsVersionDropdown" …
hrumhurum Jan 19, 2025
88e306c
feat(theme): add versions attribute to docsVersionDropdown navbar ite…
hrumhurum Jan 20, 2025
9088e6c
docs(theme): added "configuring versioning representation" section to…
hrumhurum Jan 20, 2025
f74b638
docs(theme): add versions attribute to docsVersionDropdown navbar ite…
hrumhurum Jan 20, 2025
1f3ec76
docs(theme): add versions attribute to docsVersionDropdown navbar ite…
hrumhurum Jan 20, 2025
8cbdf68
docs(theme): add versions attribute to docsVersionDropdown navbar ite…
hrumhurum Jan 26, 2025
afd9b83
feat(theme): add versions attribute to docsVersionDropdown navbar ite…
hrumhurum Jan 27, 2025
70f367a
feat(theme): add versions attribute to docsVersionDropdown navbar ite…
hrumhurum Jan 27, 2025
578bcca
feat(theme): add versions attribute to docsVersionDropdown navbar ite…
hrumhurum Jan 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/docusaurus-theme-classic/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
import {themes} from 'prism-react-renderer';
import {Joi, URISchema} from '@docusaurus/utils-validation';
import type {Options, PluginOptions} from '@docusaurus/theme-classic';
import type {
PropVersionItem,
PropVersionItems,
} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
import type {ThemeConfig} from '@docusaurus/theme-common';
import type {
ThemeConfigValidationContext,
Expand Down Expand Up @@ -210,6 +214,15 @@ const DocsVersionDropdownNavbarItemSchema = NavbarItemBaseSchema.append({
dropdownActiveClassDisabled: Joi.boolean(),
dropdownItemsBefore: Joi.array().items(DropdownSubitemSchema).default([]),
dropdownItemsAfter: Joi.array().items(DropdownSubitemSchema).default([]),
versions: Joi.alternatives().try(
Joi.array().items(Joi.string().min(1)),
Joi.object<PropVersionItems>().pattern(
Joi.string().min(1),
Joi.object<PropVersionItem>({
label: Joi.string().min(1),
}),
),
),
hrumhurum marked this conversation as resolved.
Show resolved Hide resolved
});

const LocaleDropdownNavbarItemSchema = NavbarItemBaseSchema.append({
Expand Down
11 changes: 11 additions & 0 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1257,11 +1257,22 @@ declare module '@theme/NavbarItem/DocsVersionDropdownNavbarItem' {
import type {Props as DropdownNavbarItemProps} from '@theme/NavbarItem/DropdownNavbarItem';
import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem';

type PropVersionItem = {
readonly label?: string;
};

type PropVersionItems = {
readonly [version: string]: PropVersionItem;
};

type PropVersions = string[] | PropVersionItems;

export interface Props extends DropdownNavbarItemProps {
readonly docsPluginId?: string;
readonly dropdownActiveClassDisabled?: boolean;
readonly dropdownItemsBefore: LinkLikeNavbarItemProps[];
readonly dropdownItemsAfter: LinkLikeNavbarItemProps[];
readonly versions?: PropVersions;
}

export default function DocsVersionDropdownNavbarItem(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,82 @@ import {translate} from '@docusaurus/Translate';
import {useLocation} from '@docusaurus/router';
import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
import type {Props} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
import type {
Props,
PropVersions,
PropVersionItem,
} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem';
import type {
GlobalVersion,
GlobalDoc,
ActiveDocContext,
} from '@docusaurus/plugin-content-docs/client';

type VersionConfiguration = {name: string} & PropVersionItem;

function getVersionConfigurations(
versions: PropVersions,
): VersionConfiguration[] {
if (Array.isArray(versions)) {
return versions.map((name): VersionConfiguration => {
return {name};
});
} else {
return Object.entries(versions).map(
([name, version]): VersionConfiguration => {
return {name, ...version};
},
);
}
}

type ConfiguredVersion = {
version: GlobalVersion;
configuration?: VersionConfiguration;
};

function configureVersions(
hrumhurum marked this conversation as resolved.
Show resolved Hide resolved
versions: GlobalVersion[],
staticVersions?: PropVersions,
): ConfiguredVersion[] {
if (staticVersions) {
// The versions are configured

// Collect all the versions we have
const versionMap = new Map<string, GlobalVersion>(
versions.map((version) => [version.name, version]),
);

// Add secondary version identifiers to make the configuration process
// more natural to a user
for (const version of versions) {
// 'version.name' has special conventions for current and next versions,
// that's why we use 'version.label' as a secondary version identifier
// that can be referenced in configuration
const label = version.label;
if (!versionMap.has(label)) versionMap.set(label, version);
hrumhurum marked this conversation as resolved.
Show resolved Hide resolved
}

// Keep only versions specified in configuration, reorder them accordingly
const configuredVersions: ConfiguredVersion[] = [];
for (const configuration of getVersionConfigurations(staticVersions)) {
const version = versionMap.get(configuration.name);
if (!version) {
// A version configuration references a non-existing version, ignore it
continue;
}
configuredVersions.push({version, configuration});
}
return configuredVersions;
} else {
// The versions are not configured
return versions.map((version): ConfiguredVersion => {
return {version};
});
}
}

function getVersionMainDoc(version: GlobalVersion): GlobalDoc {
return version.docs.find((doc) => doc.id === version.mainDocId)!;
}
Expand All @@ -46,17 +114,27 @@ export default function DocsVersionDropdownNavbarItem({
dropdownActiveClassDisabled,
dropdownItemsBefore,
dropdownItemsAfter,
versions: staticVersions,
...props
}: Props): ReactNode {
// Build version list
const configuredVersions = configureVersions(
useVersions(docsPluginId),
staticVersions,
);

// Build item list
const {search, hash} = useLocation();
const activeDocContext = useActiveDocContext(docsPluginId);
const versions = useVersions(docsPluginId);
const {savePreferredVersionName} = useDocsPreferredVersion(docsPluginId);

function versionToLink(version: GlobalVersion): LinkLikeNavbarItemProps {
function versionToLink(
version: GlobalVersion,
versionConfiguration?: VersionConfiguration,
): LinkLikeNavbarItemProps {
const targetDoc = getVersionTargetDoc(version, activeDocContext);
return {
label: version.label,
label: versionConfiguration?.label ?? version.label,
// preserve ?search#hash suffix on version switches
to: `${targetDoc.path}${search}${hash}`,
isActive: () => version === activeDocContext.activeVersion,
Expand All @@ -66,7 +144,7 @@ export default function DocsVersionDropdownNavbarItem({

const items: LinkLikeNavbarItemProps[] = [
...dropdownItemsBefore,
...versions.map(versionToLink),
...configuredVersions.map((x) => versionToLink(x.version, x.configuration)),
...dropdownItemsAfter,
];

Expand Down
12 changes: 12 additions & 0 deletions website/docs/api/themes/theme-configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -597,11 +597,23 @@ Accepted fields:
| `dropdownItemsAfter` | <code>[LinkLikeItem](#navbar-dropdown)[]</code> | `[]` | Add additional dropdown items at the end of the dropdown. |
| `docsPluginId` | `string` | `'default'` | The ID of the docs plugin that the doc versioning belongs to. |
| `dropdownActiveClassDisabled` | `boolean` | `false` | Do not add the link active class when browsing docs. |
| `versions` | `DropdownVersions` | `undefined` | Specify a custom list of versions to include in the dropdown. See [the versioning guide](../../../versioning#configuring-representation) for details. |

```mdx-code-block
</APITable>
```

Types:

```ts
type DropdownVersion = {
/** The custom name to be shown in the dropdown for this version. */
label?: string;
};

type DropdownVersions = string[] | {[versionName: string]: DropdownVersion};
```

Example configuration:

```js title="docusaurus.config.js"
Expand Down
72 changes: 72 additions & 0 deletions website/docs/guides/docs/versioning.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,78 @@ These links would all look for an appropriate version to link to, in the followi
2. **Preferred version**: the version that the user last viewed. If there's no history, fall back to...
3. **Latest version**: the default version that we navigate to, configured by the `lastVersion` option.

## Configuring representation of versions {#configuring-representation}
hrumhurum marked this conversation as resolved.
Show resolved Hide resolved

By default, the [`docsVersionDropdown`](../../api/themes/theme-configuration.mdx#navbar-docs-version-dropdown) displays all the versions provided by the docs.
However, sometimes it may be beneficial to restrict the number of displayed versions to simplify the user experience.
To achieve that, it is possible to specify a custom list of versions that should be offered in the dropdown:

```js title="docusaurus.config.js"
export default {
themeConfig: {
navbar: {
items: [
{
type: 'docsVersionDropdown',
// highlight-start
versions: ['2024.3', '2024.2', '2024.1', '2023.4'],
// highlight-end
},
],
},
},
};
```

Some versioning schemes may benefit from an even more detailed configuration of displayed versions.
For example, if you are using semantic versioning, you may have versions such as:

```
2.1.1
2.1.0
2.0.1
2.0.0
1.0.1
1.0.0
```

And maybe you want to have them in the dropdown as:

```
2.1
2.0
1.0
```

or maybe just:

```
1.x
2.x
```

To achieve that, you can specify a custom configuration for every version that should be displayed in the dropdown:

```js title="docusaurus.config.js"
export default {
themeConfig: {
navbar: {
items: [
{
type: 'docsVersionDropdown',
// highlight-start
versions: {
'1.0.1': {label: '1.x'},
'2.1.1': {label: '2.x'},
},
// highlight-end
},
],
},
},
};
```

## Recommended practices {#recommended-practices}

### Version your documentation only when needed {#version-your-documentation-only-when-needed}
Expand Down
Loading