Skip to content

Commit e4d6117

Browse files
authored
feat: [#101] footer component
* feat: footer component
1 parent 9b7352d commit e4d6117

File tree

14 files changed

+173
-7
lines changed

14 files changed

+173
-7
lines changed

src/components/footer/index.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { insertAllSocials } from "../socials";
2+
3+
export type FooterLinkItem = [
4+
name: string,
5+
path: string,
6+
]
7+
8+
const copyrightText = `© All rights reserved ${new Date().getFullYear()} / cd-labs`;
9+
10+
//-----------------------------------------------------------------------
11+
12+
export function buildFooter(links: FooterLinkItem[] = []) {
13+
const footer = document.createElement("footer");
14+
footer.id = "main-footer";
15+
16+
// Create a container for socials and copyrights on the same line
17+
const footerContent = document.createElement("div");
18+
footerContent.className = "footer-content";
19+
20+
const socials = insertAllSocials();
21+
socials.classList.add('footer-socials');
22+
23+
const copyrights = document.createElement("p");
24+
copyrights.className = "copyrights";
25+
copyrights.textContent = copyrightText;
26+
27+
// Add socials first (left side), then copyrights
28+
footerContent.appendChild(socials);
29+
footerContent.appendChild(copyrights);
30+
footer.appendChild(footerContent);
31+
32+
return footer;
33+
}
Lines changed: 5 additions & 0 deletions
Loading
Lines changed: 5 additions & 0 deletions
Loading
Lines changed: 6 additions & 0 deletions
Loading

src/components/socials/index.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import GITHUB_ICON from './assets/github-icon.svg';
2+
import LINKEDIN_ICON from './assets/linkedin-icon.svg';
3+
import INSTAGRAM_ICON from './assets/instagram-icon.svg';
4+
5+
type social = {
6+
name: string;
7+
url: string;
8+
iconSrc: string;
9+
}
10+
11+
export const socials: social[] = [
12+
{
13+
name: 'GitHub',
14+
url: 'https://github.com/cd-bash',
15+
iconSrc: GITHUB_ICON,
16+
},
17+
{
18+
name: 'LinkedIn',
19+
url: 'https://www.linkedin.com/in/charlesdouc/',
20+
iconSrc: LINKEDIN_ICON,
21+
},
22+
{
23+
name: 'Instagram',
24+
url: 'https://www.instagram.com/cd.oucet/',
25+
iconSrc: INSTAGRAM_ICON,
26+
},
27+
]
28+
29+
//-----------------------------------------------------------------------
30+
31+
export function insertAllSocials() {
32+
const container = document.createElement('ul');
33+
container.className = 'social-icons';
34+
35+
socials.forEach(social => {
36+
const li = document.createElement('li');
37+
const a = document.createElement('a');
38+
a.href = social.url;
39+
a.target = '_blank';
40+
a.rel = 'noopener noreferrer';
41+
42+
const img = document.createElement('img');
43+
img.src = social.iconSrc;
44+
img.alt = `${social.name} Icon`;
45+
img.className = 'social-icon';
46+
47+
a.appendChild(img);
48+
li.appendChild(a);
49+
container.appendChild(li);
50+
});
51+
52+
return container;
53+
}

src/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { router } from "./core/router";
2-
import {homeView, aboutView, buildViewBase, renderView, logArticleView } from "./views";
2+
import {homeView, aboutView, buildViewBase, renderView, logArticleView, contactView} from "./views";
33
import {buildNavigation} from "./components/navigation";
44
import {changeLogoOnScroll} from "./components/navigation/logo";
5+
import { buildFooter } from "./components/footer";
56

67

78
const routes = [
89
{ path: '', handler: () => renderView(homeView()) },
910
{ path: '/about', handler: () => renderView(aboutView()) },
10-
{ path: '/logs', handler: () => renderView(logArticleView()) }
11+
{ path: '/logs', handler: () => renderView(logArticleView()) },
12+
{ path: '/contact', handler: () => renderView(contactView()) }
1113
];
1214

1315
routes.forEach(route => router.registerRoute(route.path, route.handler));
@@ -18,12 +20,13 @@ function init() {
1820
const body = document.getElementsByTagName("body")[0];
1921
const contentPage = buildViewBase();
2022
const nav = buildNavigation();
23+
const footer = buildFooter();
2124

2225
body.appendChild(nav);
2326
window.addEventListener('scroll', changeLogoOnScroll);
2427

2528
body.appendChild(contentPage);
26-
29+
body.appendChild(footer);
2730

2831
router.handleRoute(window.location.pathname);
2932
}

src/styles/base/variables.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
--font-secondary: 'Handjet', serif;
1919

2020
/* Font Sizes */
21+
--text-3xs: clamp(0.6rem, 1vw, 0.7rem);
22+
--text-2xs: clamp(0.7rem, 1.5vw, 0.8rem);
2123
--text-xs: clamp(0.8rem, 2vw, 0.9rem);
2224
--text-sm: clamp(0.9rem, 2.5vw, 1.1rem);
2325
--text-base: clamp(1.1rem, 3vw, 1.5rem);

src/styles/components/call-to-action.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
.cta-banner article {
1919
position: relative;
2020
z-index: var(--z-content);
21-
padding: var(--space-md) var(--space-lg);
21+
padding: var(--space-md) 0;
2222
background-color: white;
2323
width: fit-content;
2424
display: grid;
@@ -49,10 +49,12 @@
4949
/* -------------------------------------------------------------------------- */
5050
.cta-banner article.right {
5151
margin-left: auto;
52+
padding-left: var(--space-lg);
5253
}
5354

5455
.cta-banner article.left {
5556
margin-right: auto;
57+
padding-right: var(--space-lg);
5658
}
5759

5860
/* -------------------------------------------------------------------------- */
@@ -97,6 +99,8 @@
9799
.cta-banner article.right, .cta-banner article.left {
98100
margin-left: 0;
99101
margin-right: 0;
102+
padding-left: 0;
103+
padding-right: 0;
100104
}
101105

102106
.cta-banner ul {

src/styles/components/footer.css

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* ==========================================================================
2+
Footer Component
3+
========================================================================== */
4+
5+
#main-footer {
6+
min-height: 75px;
7+
width: 85%;
8+
margin: 0 auto;
9+
10+
.footer-content {
11+
display: flex;
12+
align-items: center;
13+
justify-content: space-between;
14+
padding: var(--space-md) 0;
15+
border-top: 1px solid var(--color-border);
16+
gap: var(--space-md);
17+
}
18+
19+
.footer-socials {
20+
order: 1; /* Ensures socials come first */
21+
flex-shrink: 0; /* Prevents shrinking */
22+
}
23+
24+
.copyrights {
25+
order: 2; /* Ensures copyrights come second */
26+
margin: 0;
27+
font-size: var(--text-3xs);
28+
text-transform: uppercase;
29+
color: var(--color-text-secondary);
30+
text-align: left;
31+
flex-grow: 1; /* Takes remaining space */
32+
}
33+
}

src/styles/components/socials.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* ==========================================================================
2+
Socials Component
3+
========================================================================== */
4+
5+
.social-icons {
6+
list-style: none;
7+
display: flex;
8+
gap: var(--space-sm);
9+
10+
img {
11+
width: 30px;
12+
height: 30px;
13+
filter: var(--filter-icon);
14+
transition: filter var(--transition-base);
15+
16+
&:hover {
17+
filter: var(--filter-icon-hover);
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)