umberto 10.3.0 → 10.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -7
- package/package.json +1 -1
- package/src/tasks/build-documentation.js +6 -0
- package/themes/umberto/layout/gloria/_components/dropdown/index.pug +5 -2
- package/themes/umberto/layout/gloria/_modules/header/nav-project-select-dropdown.pug +46 -3
- package/themes/umberto/layout/gloria/_modules/mobile-nav/index.pug +40 -5
- package/themes/umberto/layout/gloria/_modules/mobile-nav/slide-parts.pug +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
## [10.4.0](https://github.com/cksource/umberto/compare/v10.3.0...v10.4.0) (April 9, 2026)
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Added the LTS edition to the docs product picker.
|
|
9
|
+
|
|
10
|
+
|
|
4
11
|
## [10.3.0](https://github.com/cksource/umberto/compare/v10.2.0...v10.3.0) (April 3, 2026)
|
|
5
12
|
|
|
6
13
|
### Features
|
|
@@ -40,13 +47,6 @@ Changelog
|
|
|
40
47
|
|
|
41
48
|
* Fix regression introduced in `v10.1.2` affecting slugs generated for headings. Slugs generated now should be the same as in `v10.1.1` and previous versions of Umberto.
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
## [10.1.2](https://github.com/cksource/umberto/compare/v10.1.1...v10.1.2) (March 9, 2026)
|
|
45
|
-
|
|
46
|
-
### Bug fixes
|
|
47
|
-
|
|
48
|
-
* Removed unmaintained `hexo-renderer-markdown-it-plus` and `@ckeditor/jsdoc-plugins` dependencies by replacing them with maintained and local implementations, resolving the reported `markdown-it`-related vulnerabilities in Umberto's dependency tree.
|
|
49
|
-
|
|
50
50
|
---
|
|
51
51
|
|
|
52
52
|
To see all releases, visit the [release page](https://github.com/cksource/umberto/releases).
|
package/package.json
CHANGED
|
@@ -161,6 +161,12 @@ export const buildDocumentation = options => {
|
|
|
161
161
|
macrosVariables: mainConfig.variables,
|
|
162
162
|
quickNavigationProjects: mainConfig.quickNavigationProjects || [
|
|
163
163
|
{ name: 'CKEditor 5', slug: 'ckeditor5' },
|
|
164
|
+
{
|
|
165
|
+
name: 'CKEditor 5 LTS Edition',
|
|
166
|
+
slug: 'ckeditor5',
|
|
167
|
+
channel: 'lts-v47',
|
|
168
|
+
rel: 'nofollow'
|
|
169
|
+
},
|
|
164
170
|
{ name: 'Cloud Services', slug: 'cs' },
|
|
165
171
|
{ name: 'CKBox', slug: 'ckbox' }
|
|
166
172
|
],
|
|
@@ -50,20 +50,23 @@ mixin dropdown({ id: dropdownId, className, preferredDirection, contentId, updat
|
|
|
50
50
|
//- +dropdown-item({ label: 'Active item', active: true })
|
|
51
51
|
//- +dropdown-item({ label: 'Item with value', value: 'custom-value' })
|
|
52
52
|
//- +dropdown-item({ label: 'Item with icon', icon: 'github' })
|
|
53
|
-
//- +dropdown-item({ label: 'Custom link', href: '/custom-link' })
|
|
53
|
+
//- +dropdown-item({ label: 'Custom link', href: '/custom-link', rel: 'nofollow' })
|
|
54
54
|
//- +dropdown-item({ label: 'With ID', itemId: 'special-item' })
|
|
55
|
-
mixin dropdown-item({ itemId, href, active = false, narrow, label, icon, value } = {})
|
|
55
|
+
mixin dropdown-item({ itemId, href, rel, active = false, narrow, label, icon, value, projectSlug, projectChannel } = {})
|
|
56
56
|
- const tag = href ? 'a' : 'div';
|
|
57
57
|
|
|
58
58
|
li.c-dropdown__list-item
|
|
59
59
|
#{tag}.b-reset-link.c-dropdown__item(
|
|
60
60
|
role='menuitem',
|
|
61
61
|
href=href,
|
|
62
|
+
rel=rel,
|
|
62
63
|
class={
|
|
63
64
|
'is-active': active,
|
|
64
65
|
'c-dropdown__item--narrow': !!narrow
|
|
65
66
|
},
|
|
66
67
|
data-item-id=itemId,
|
|
68
|
+
data-project-slug=projectSlug,
|
|
69
|
+
data-project-channel=projectChannel,
|
|
67
70
|
data-value=value,
|
|
68
71
|
tabindex='-1'
|
|
69
72
|
)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
mixin nav-project-select-dropdown()
|
|
2
2
|
-
|
|
3
|
+
const getProjectHref = project => relative_url( page.path, `${ project.slug }/${ project.channel || 'latest' }/index.html` );
|
|
3
4
|
const currentProject = projectLocals && quickNavigationProjects && quickNavigationProjects.find(
|
|
4
|
-
project => project.slug === projectLocals.projectSlug
|
|
5
|
+
project => project.slug === projectLocals.projectSlug && !project.channel
|
|
5
6
|
);
|
|
6
7
|
|
|
7
8
|
+menu-dropdown({
|
|
@@ -10,7 +11,49 @@ mixin nav-project-select-dropdown()
|
|
|
10
11
|
each project in quickNavigationProjects
|
|
11
12
|
+dropdown-item({
|
|
12
13
|
label: project.name,
|
|
13
|
-
active: !!currentProject &&
|
|
14
|
-
|
|
14
|
+
active: !!currentProject &&
|
|
15
|
+
project.slug === currentProject.slug &&
|
|
16
|
+
( project.channel || 'latest' ) === 'latest',
|
|
17
|
+
href: getProjectHref( project ),
|
|
18
|
+
rel: project.rel,
|
|
19
|
+
projectSlug: project.slug,
|
|
20
|
+
projectChannel: project.channel || 'latest'
|
|
15
21
|
})
|
|
16
22
|
|
|
23
|
+
if currentProject
|
|
24
|
+
script.
|
|
25
|
+
(function() {
|
|
26
|
+
const script = document.currentScript;
|
|
27
|
+
|
|
28
|
+
document.addEventListener( 'DOMContentLoaded', () => {
|
|
29
|
+
const dropdown = script?.previousElementSibling;
|
|
30
|
+
const currentProjectSlug = !{ JSON.stringify( currentProject.slug ) };
|
|
31
|
+
const segments = window.location.pathname.split( '/' ).filter( Boolean );
|
|
32
|
+
const slugIndex = segments.indexOf( currentProjectSlug );
|
|
33
|
+
|
|
34
|
+
if ( !dropdown || slugIndex < 0 ) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const rawChannel = segments[ slugIndex + 1 ];
|
|
39
|
+
const currentChannel = /^\d+\.\d+\.\d+$/.test( rawChannel || '' ) ? 'latest' : ( rawChannel || 'latest' );
|
|
40
|
+
const items = Array.from( dropdown.querySelectorAll( '.c-dropdown__item[data-project-slug][data-project-channel]' ) );
|
|
41
|
+
const activeItem = items.find( item => item.dataset.projectSlug === currentProjectSlug && item.dataset.projectChannel === currentChannel );
|
|
42
|
+
|
|
43
|
+
if ( !activeItem ) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for ( const item of items ) {
|
|
48
|
+
item.classList.toggle( 'is-active', item === activeItem );
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const labelElement = dropdown.querySelector( '.c-menu-dropdown__button .c-button__label' );
|
|
52
|
+
const labelText = activeItem.querySelector( 'span' )?.textContent?.trim() || activeItem.textContent.trim();
|
|
53
|
+
|
|
54
|
+
if ( labelElement && labelText ) {
|
|
55
|
+
labelElement.textContent = labelText;
|
|
56
|
+
}
|
|
57
|
+
}, { once: true } );
|
|
58
|
+
})();
|
|
59
|
+
|
|
@@ -3,6 +3,7 @@ include ./slide-parts
|
|
|
3
3
|
mixin mobile-nav()
|
|
4
4
|
-
|
|
5
5
|
const currentProject = projectLocals && projectsData.find( project => project.slug === projectLocals.projectSlug );
|
|
6
|
+
const getProjectHref = project => relative_url( page.path, `${ project.slug }/${ project.channel || 'latest' }/index.html` );
|
|
6
7
|
let initialSlideId = projectLocals ? `project-${projectLocals.projectSlug}` : 'products';
|
|
7
8
|
|
|
8
9
|
// If the page has a category, set the initial slide to that category's slide
|
|
@@ -23,20 +24,54 @@ mixin mobile-nav()
|
|
|
23
24
|
if quickNavigationProjects
|
|
24
25
|
ol.b-reset-list.c-mobile-nav__items
|
|
25
26
|
each project in quickNavigationProjects
|
|
26
|
-
- isCurrentProject = projectLocals && project.slug === projectLocals.projectSlug
|
|
27
|
-
|
|
27
|
+
- isCurrentProject = projectLocals && project.slug === projectLocals.projectSlug && !project.channel
|
|
28
28
|
if isCurrentProject
|
|
29
29
|
+mobile-nav-item({
|
|
30
30
|
label: project.name,
|
|
31
31
|
active: true,
|
|
32
|
-
targetSlideId: `project-${ project.slug }
|
|
32
|
+
targetSlideId: `project-${ project.slug }`,
|
|
33
|
+
projectSlug: project.slug,
|
|
34
|
+
projectChannel: project.channel || 'latest'
|
|
33
35
|
})
|
|
34
36
|
else
|
|
35
37
|
+mobile-nav-item({
|
|
36
|
-
href:
|
|
37
|
-
label: project.name
|
|
38
|
+
href: getProjectHref( project ),
|
|
39
|
+
label: project.name,
|
|
40
|
+
rel: project.rel,
|
|
41
|
+
projectSlug: project.slug,
|
|
42
|
+
projectChannel: project.channel || 'latest'
|
|
38
43
|
})
|
|
39
44
|
|
|
45
|
+
if currentProject
|
|
46
|
+
script.
|
|
47
|
+
(function() {
|
|
48
|
+
const script = document.currentScript;
|
|
49
|
+
|
|
50
|
+
document.addEventListener( 'DOMContentLoaded', () => {
|
|
51
|
+
const mobileNav = script?.previousElementSibling;
|
|
52
|
+
const currentProjectSlug = !{ JSON.stringify( currentProject.slug ) };
|
|
53
|
+
const segments = window.location.pathname.split( '/' ).filter( Boolean );
|
|
54
|
+
const slugIndex = segments.indexOf( currentProjectSlug );
|
|
55
|
+
|
|
56
|
+
if ( !mobileNav || slugIndex < 0 ) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const rawChannel = segments[ slugIndex + 1 ];
|
|
61
|
+
const currentChannel = /^\d+\.\d+\.\d+$/.test( rawChannel || '' ) ? 'latest' : ( rawChannel || 'latest' );
|
|
62
|
+
const items = Array.from( mobileNav.querySelectorAll( '.c-mobile-nav__item[data-project-slug][data-project-channel]' ) );
|
|
63
|
+
const activeItem = items.find( item => item.dataset.projectSlug === currentProjectSlug && item.dataset.projectChannel === currentChannel );
|
|
64
|
+
|
|
65
|
+
if ( !activeItem ) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for ( const item of items ) {
|
|
70
|
+
item.classList.toggle( 'is-active', item === activeItem );
|
|
71
|
+
}
|
|
72
|
+
}, { once: true } );
|
|
73
|
+
})();
|
|
74
|
+
|
|
40
75
|
//- Current project slide
|
|
41
76
|
if projectLocals
|
|
42
77
|
+mobile-nav-slide({ slideId: `project-${ projectLocals.projectSlug }` })
|
|
@@ -32,7 +32,7 @@ mixin mobile-nav-heading({ href, label })
|
|
|
32
32
|
iconPosition: 'right',
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
mixin mobile-nav-item({ href, label, targetSlideId, target, active = false })
|
|
35
|
+
mixin mobile-nav-item({ href, label, rel, targetSlideId, target, active = false, projectSlug, projectChannel })
|
|
36
36
|
li
|
|
37
37
|
if targetSlideId
|
|
38
38
|
+button({
|
|
@@ -48,11 +48,16 @@ mixin mobile-nav-item({ href, label, targetSlideId, target, active = false })
|
|
|
48
48
|
'data-navigate-direction'='forward',
|
|
49
49
|
'aria-controls'=`slide-${targetSlideId}`,
|
|
50
50
|
'aria-expanded'='false',
|
|
51
|
-
'aria-haspopup'='true'
|
|
51
|
+
'aria-haspopup'='true',
|
|
52
|
+
'data-project-slug'=projectSlug,
|
|
53
|
+
'data-project-channel'=projectChannel
|
|
52
54
|
)
|
|
53
55
|
else
|
|
54
56
|
a.b-link.c-mobile-nav__item(
|
|
55
57
|
href=href,
|
|
58
|
+
rel=rel,
|
|
59
|
+
data-project-slug=projectSlug,
|
|
60
|
+
data-project-channel=projectChannel,
|
|
56
61
|
class=active ? 'is-active' : '',
|
|
57
62
|
target=target
|
|
58
63
|
)= label
|