Skip to content

Commit d0cb186

Browse files
committed
feat: Modernize Portal Footer and Enable Theming (#8852, #8853)
- Refactor FooterContainer layout to VBox with flex columns - Enable full theming support (Light/Dark) with semantic tokens - Align layout padding with page content (AiToolchain) - Fix hover effects and contrast issues
1 parent eb4f3f2 commit d0cb186

File tree

4 files changed

+171
-126
lines changed

4 files changed

+171
-126
lines changed

apps/portal/view/home/FooterContainer.mjs

Lines changed: 86 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -23,99 +23,112 @@ class FooterContainer extends Container {
2323
*/
2424
itemDefaults: {
2525
module: Container,
26-
cls : ['portal-home-footer-section'],
27-
layout: {ntype: 'vbox', align: 'start'},
26+
cls : ['portal-footer-content'],
27+
layout: {ntype: 'hbox', align: 'start', pack: 'start'},
28+
style : {width: '100%'},
2829

2930
itemDefaults: {
30-
module: Button,
31-
ui : 'ghost'
31+
module: Container,
32+
cls : ['portal-home-footer-section'],
33+
flex : 1,
34+
layout: {ntype: 'vbox', align: 'start'},
35+
36+
itemDefaults: {
37+
module: Button,
38+
ui : 'ghost'
39+
}
3240
}
3341
},
3442
/**
3543
* @member {Object[]} items
3644
*/
3745
items: [{
3846
items: [{
39-
module: Component,
40-
cls : ['neo-h2'],
41-
tag : 'h2',
42-
text : 'Content'
43-
}, {
44-
iconCls: 'fas fa-people-group',
45-
route : '/about-us',
46-
text : 'About Us'
47-
}, {
48-
iconCls: 'fas fa-book',
49-
route : '/docs',
50-
text : 'API Docs'
51-
}, {
52-
iconCls: 'fas fa-blog',
53-
route : '/blog',
54-
text : 'Blog'
55-
}, {
56-
iconCls: 'fas fa-graduation-cap',
57-
route : '/learn',
58-
text : 'Learn'
59-
}, {
60-
iconCls: 'fas fa-handshake-angle',
61-
route : '/services',
62-
text : 'Services'
63-
}]
64-
}, {
65-
items: [{
66-
module: Component,
67-
cls : ['neo-h2'],
68-
tag : 'h2',
69-
text : 'Community'
47+
items: [{
48+
module: Component,
49+
cls : ['neo-h3'],
50+
tag : 'h3',
51+
text : 'Content'
52+
}, {
53+
iconCls: 'fas fa-people-group',
54+
route : '/about-us',
55+
text : 'About Us'
56+
}, {
57+
iconCls: 'fas fa-book',
58+
route : '/docs',
59+
text : 'API Docs'
60+
}, {
61+
iconCls: 'fas fa-blog',
62+
route : '/blog',
63+
text : 'Blog'
64+
}, {
65+
iconCls: 'fas fa-graduation-cap',
66+
route : '/learn',
67+
text : 'Learn'
68+
}, {
69+
iconCls: 'fas fa-handshake-angle',
70+
route : '/services',
71+
text : 'Services'
72+
}]
7073
}, {
71-
iconCls: 'fa-brands fa-github',
72-
text : 'Contribute',
73-
url : 'https://github.com/neomjs/neo/blob/dev/CONTRIBUTING.md'
74+
items: [{
75+
module: Component,
76+
cls : ['neo-h3'],
77+
tag : 'h3',
78+
text : 'Community'
79+
}, {
80+
iconCls: 'fa-brands fa-github',
81+
text : 'Contribute',
82+
url : 'https://github.com/neomjs/neo/blob/dev/CONTRIBUTING.md'
83+
}, {
84+
iconCls: 'fa-brands fa-github',
85+
text : 'Code of Conduct',
86+
url : 'https://github.com/neomjs/neo/blob/dev/.github/CODE_OF_CONDUCT.md'
87+
}, {
88+
iconCls: 'fa-brands fa-github',
89+
text : 'Report Issues',
90+
url : 'https://github.com/neomjs/neo/issues'
91+
}, {
92+
iconCls: 'fa-brands fa-slack',
93+
text : 'Slack',
94+
url : 'https://join.slack.com/t/neomjs/shared_invite/zt-6c50ueeu-3E1~M4T9xkNnb~M_prEEOA'
95+
}, {
96+
iconCls: 'fa-brands fa-discord',
97+
text : 'Discord',
98+
url : 'https://discord.gg/6p8paPq'
99+
}]
74100
}, {
75-
iconCls: 'fa-brands fa-github',
76-
text : 'Code of Conduct',
77-
url : 'https://github.com/neomjs/neo/blob/dev/.github/CODE_OF_CONDUCT.md'
78-
}, {
79-
iconCls: 'fa-brands fa-github',
80-
text : 'Report Issues',
81-
url : 'https://github.com/neomjs/neo/issues'
82-
}, {
83-
iconCls: 'fa-brands fa-slack',
84-
text : 'Slack',
85-
url : 'https://join.slack.com/t/neomjs/shared_invite/zt-6c50ueeu-3E1~M4T9xkNnb~M_prEEOA'
86-
}, {
87-
iconCls: 'fa-brands fa-discord',
88-
text : 'Discord',
89-
url : 'https://discord.gg/6p8paPq'
101+
items: [{
102+
module: Component,
103+
cls : ['neo-h3'],
104+
tag : 'h3',
105+
text : 'Social Media'
106+
}, {
107+
iconCls: 'fa-brands fa-linkedin',
108+
text : 'LinkedIn',
109+
url : 'https://www.linkedin.com/company/neo-mjs/'
110+
}, {
111+
iconCls: 'fa-brands fa-facebook',
112+
text : 'Facebook',
113+
url : 'https://www.facebook.com/neo.mjs'
114+
}]
90115
}]
91116
}, {
92-
items: [{
93-
module: Component,
94-
cls : ['neo-h2'],
95-
tag : 'h2',
96-
text : 'Social Media'
97-
}, {
98-
iconCls: 'fa-brands fa-linkedin',
99-
text : 'LinkedIn',
100-
url : 'https://www.linkedin.com/company/neo-mjs/'
101-
}, {
102-
iconCls: 'fa-brands fa-facebook',
103-
text : 'Facebook',
104-
url : 'https://www.facebook.com/neo.mjs'
105-
}, {
106-
module: Component,
107-
cls : ['portal-home-footer-spacer']
108-
}, {
117+
module: Container,
118+
cls : ['portal-footer-bottom'],
119+
flex : 'none',
120+
layout: {ntype: 'hbox', align: 'center', pack: 'center'},
121+
items : [{
109122
module: Component,
110123
cls : ['neo-version'],
111-
text : 'v11.22.0'
124+
text : '© 2026 Neo.mjs • v11.22.0 • MIT License'
112125
}]
113126
}],
114127
/**
115-
* @member {Object} layout={ntype:'hbox',align:'stretch'}
128+
* @member {Object} layout={ntype:'vbox',align:'stretch'}
116129
* @reactive
117130
*/
118-
layout: {ntype: 'hbox', align: 'stretch'},
131+
layout: {ntype: 'vbox', align: 'stretch'},
119132
/**
120133
* @member {String} tag='footer'
121134
* @reactive
Lines changed: 69 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,89 @@
11
.portal-home-footer-container {
2-
background-color: black;
3-
height : 35%;
4-
padding : 2em;
2+
background-color: var(--portal-footer-background-color);
3+
color : var(--portal-footer-text-color);
4+
display : flex;
5+
flex-direction : column;
6+
min-height : 300px;
7+
padding : 0 2em;
8+
width : 100%;
59

6-
.neo-button.neo-button-ghost {
7-
justify-content: start;
8-
min-width : 10em;
10+
.portal-footer-content {
11+
background-color: transparent;
12+
color : inherit;
13+
gap : 2em;
14+
margin : 0 auto;
15+
max-width : 1200px;
16+
padding : 4em 0;
17+
width : 100%;
918

10-
&:hover {
11-
background-color: #333;
19+
@media (max-width: 800px) {
20+
flex-direction: column !important;
21+
gap : 3em;
22+
padding : 3em 0;
1223
}
24+
}
1325

14-
.neo-button-glyph {
15-
color : white;
16-
font-size: 16px;
17-
}
26+
.portal-home-footer-section {
27+
background-color: transparent;
28+
color : inherit;
29+
flex : 1;
1830

19-
.neo-button-text {
20-
color: white;
31+
h3.neo-h3 {
32+
color : var(--portal-footer-text-color);
33+
font-size : 1.1rem;
34+
font-weight : 600;
35+
letter-spacing: 0.5px;
36+
margin-bottom : 1.5em;
37+
opacity : 0.9;
38+
text-transform: uppercase;
2139
}
22-
}
2340

24-
h2.neo-h2 {
25-
color: white;
26-
}
41+
.neo-button.neo-button-ghost {
42+
--button-ghost-glyph-color : var(--portal-footer-text-color);
43+
--button-ghost-glyph-color-hover : var(--portal-footer-highlight-color);
44+
--button-ghost-text-color : var(--portal-footer-text-color);
45+
--button-ghost-text-color-hover : var(--portal-footer-highlight-color);
2746

28-
.neo-version {
29-
align-items: center;
30-
display : flex;
31-
padding : var(--button-padding);
32-
}
47+
justify-content: flex-start;
48+
margin-bottom : 0.5em;
49+
padding-left : 0;
3350

34-
.neo-version {
35-
height: var(--button-height);
36-
margin: var(--button-margin);
37-
}
51+
&:hover {
52+
background-color: var(--portal-footer-button-hover-background-color);
53+
border-radius : 4px;
54+
}
3855

39-
.portal-home-footer-spacer {
40-
height: calc(2 * var(--button-height));
41-
margin: calc(2 * var(--button-margin));
42-
}
56+
.neo-button-glyph {
57+
font-size : 14px;
58+
margin-right: 0.8em;
59+
opacity : 0.7;
60+
width : 16px;
61+
}
4362

44-
.portal-home-footer-section {
45-
background-color: transparent;
46-
color : white;
47-
}
63+
.neo-button-text {
64+
font-size: 0.95rem;
65+
opacity : 0.8;
66+
}
4867

49-
.portal-home-footer-spacer {
50-
height: calc(2 * var(--button-height));
51-
margin: calc(2 * var(--button-margin));
68+
&:hover .neo-button-text,
69+
&:hover .neo-button-glyph {
70+
opacity: 1;
71+
}
72+
}
5273
}
5374

54-
@media (max-width: 800px) {
55-
max-height: 18em;
56-
min-height: 18em;
57-
padding : 1em;
58-
59-
h2.neo-h2 {
60-
font-size: 1.2rem;
61-
}
75+
.portal-footer-bottom {
76+
background-color: transparent;
77+
border-top : 1px solid rgba(128, 128, 128, 0.2);
78+
color : inherit;
79+
padding : 2em 0;
6280

63-
.neo-button,
6481
.neo-version {
65-
padding: 0 3px;
82+
color : var(--portal-footer-text-color);
83+
font-size : 0.85rem;
84+
opacity : 0.6;
85+
text-align: center;
86+
width : 100%;
6687
}
6788
}
68-
69-
@media (max-width: 500px) {
70-
max-height: 15em;
71-
min-height: 15em;
72-
}
7389
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
:root .neo-theme-neo-dark {
2+
.portal-home-footer-container {
3+
--portal-footer-background-color: var(--sem-color-bg-neutral-default);
4+
--portal-footer-text-color: var(--sem-color-text-neutral-default);
5+
--portal-footer-button-hover-background-color: var(--sem-color-bg-hover);
6+
--portal-footer-highlight-color: var(--portal-headline-primary);
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
:root .neo-theme-neo-light {
2+
.portal-home-footer-container {
3+
--portal-footer-background-color: var(--sem-color-bg-neutral-strong);
4+
--portal-footer-text-color: var(--sem-color-text-neutral-default);
5+
--portal-footer-button-hover-background-color: rgba(0, 0, 0, 0.05);
6+
--portal-footer-highlight-color: var(--portal-headline-primary);
7+
}
8+
}

0 commit comments

Comments
 (0)