Restructure to classic static-site layout, add project-card component, fix bugs

- Move wwwroot/ to public/ with assets/ grouping (css, js, img, fonts, vid)
- Inline section includes into index.html, drop runtime fetch loading
- Add project-card web component to replace repeated project markup
- Fix IntersectionObserver options placement bug in nav highlight
- Fix @font-face syntax, invalid 5-digit hex colors, 75x border-radius typo
- Remove dead css link (home.css), unused purple/orange color vars
- Fix typos, replace inline styles with classes, serve favicon
This commit is contained in:
Douwe
2026-09-24 14:22:54 +00:00
parent 8ab6193103
commit 2eef84eb03
34 changed files with 385 additions and 293 deletions
+36
View File
@@ -0,0 +1,36 @@
@font-face {
font-family: 'Righteous';
src: url('/assets/fonts/Righteous-Regular.ttf') format('truetype');
font-display: swap;
}
@font-face {
font-family: 'Montserrat';
src: url('/assets/fonts/Montserrat-Regular.ttf') format('truetype');
font-display: swap;
}
@font-face {
font-family: 'Montserrat';
src: url('/assets/fonts/Montserrat-Bold.ttf') format('truetype');
font-weight: bold;
font-display: swap;
}
:root {
--background-clr: #283e3e;
--background-accent-clr: #324f4f;
--blue-clr: #47bcdf;
--green-clr: #6ede9a;
--white-clr: #ffffff;
}
body {
font-family: 'Montserrat', sans-serif;
background-color: var(--background-clr);
color: var(--white-clr);
}
.title {
font-family: 'Righteous', sans-serif;
}
+244
View File
@@ -0,0 +1,244 @@
/* ===== Base Styles ===== */
html, body {
height: 100%;
margin: 0;
padding: 0;
font-size: 25px;
}
body {
display: flex;
flex-direction: column;
}
main {
flex: 1;
margin: 20px;
overflow-y: auto;
overflow-x: hidden;
scroll-behavior: smooth;
}
a {
color: var(--blue-clr)
}
footer {
flex-shrink: 0;
background: var(--background-clr);
width: 100%;
}
footer > div {
justify-content: space-between
}
footer > div > p {
font-size: 16px;
margin: 10px 25px 10px 25px;
}
.flag {
height: 16px;
vertical-align: middle;
}
/* ===== Container Layouts ===== */
.vert_container {
display: flex;
}
@media (max-width: 1000px) {
.vert_container.revert {
display: inherit;
}
}
.vert_container.centered {
align-items: center;
justify-content: space-around;
}
.vert_container.start {
align-items: flex-start;
justify-content: space-around;
}
.scroll_container {
overflow-y: auto;
scroll-snap-type: y mandatory;
}
.scroll_section {
min-height: 100vh;
scroll-snap-align: start;
}
/* ===== Navigationbar ===== */
.nav_option {
font-family: 'Montserrat', sans-serif;
font-weight: bold;
color: var(--white-clr);
text-decoration: none;
font-size: 36px;
border: none;
border-radius: 20px;
background-color: transparent;
display: flex;
align-items: center;
margin: 10px;
padding-right: 10px;
}
.nav_option:hover {
background-color: var(--background-accent-clr);
}
.nav_option.active {
background-color: var(--background-accent-clr);
}
.nav_option span {
color: var(--green-clr);
}
@media (max-width: 1100px) {
.nav_option p {
display: none;
}
}
/* ===== Layout ===== */
.panel {
width: 60%;
}
@media (max-width: 1000px) {
.panel {
width: 100%;
}
}
.section-title {
display: flex;
align-items: flex-start;
justify-content: space-around;
}
.text-section {
margin-left: 50px;
}
.title {
font-size: 128px;
margin: 0;
line-height: 1;
text-wrap: balance;
}
@media (max-width: 1200px) {
.title {
font-size: 100px;
}
.tagline {
font-size: 26px;
width: 400px;
}
}
.tagline {
display: flex;
font-size: 36px;
font-weight: bold;
width: 500px;
}
.tagline .green-text {
color: var(--green-clr);
}
.tagline .normal-text {
margin-left: 7px;
}
.content-box {
background-color: var(--background-accent-clr);
margin: 50px 20px 20px;
padding: 20px;
border-radius: 20px;
}
.content-box p {
margin: 0;
}
.content-box .intro-text {
font-weight: bolder;
font-size: 28px;
color: var(--green-clr)
}
.project-thumb {
width: 150px;
height: 150px;
object-fit: cover;
margin-right: 15px;
border-radius: 75px;
float: left;
}
/* ===== Images ===== */
.icon {
vertical-align: middle;
padding: 10px;
}
.icon.small {
height: 45px;
}
.icon.medium {
height: 100px;
}
.icon.large {
height: 250px;
}
@media (max-width: 1200px) {
.icon.large.toggle {
height: 150px;
}
}
.image {
margin: 30px;
}
.image.large {
width: 40%;
}
.image.small {
width: 25%;
}
@media (max-width: 1000px) {
.image.large {
width: 80%;
}
.image.small {
width: 50%;
}
}
.image.stick {
position: sticky;
top: 20px
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 984 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

+45
View File
@@ -0,0 +1,45 @@
document.addEventListener('DOMContentLoaded', () => {
setupNavigationHighlight();
setupNavigationClicks();
setupCopyright();
});
function setupNavigationHighlight() {
const sections = document.querySelectorAll('.scroll_section');
const navOptions = document.querySelectorAll('.nav_option');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const sectionId = entry.target.id;
window.history.replaceState(null, null, `#${sectionId}`);
navOptions.forEach(link => {
link.classList.toggle('active', link.getAttribute('href') === `#${sectionId}`);
});
}
});
}, {
threshold: 0.5
});
sections.forEach(section => observer.observe(section));
}
function setupNavigationClicks() {
document.querySelectorAll('.nav_option').forEach(link => {
link.addEventListener('click', (event) => {
event.preventDefault();
const targetId = link.getAttribute('href');
const targetSection = document.querySelector(targetId);
if (targetSection) {
targetSection.scrollIntoView({
behavior: 'smooth'
});
}
});
});
}
function setupCopyright() {
document.getElementById('copyright').textContent = `© ${new Date().getFullYear()} - douwco.be`;
}
+101
View File
@@ -0,0 +1,101 @@
class ProjectCard extends HTMLElement {
static get observedAttributes() {
return ['image', 'image-alt', 'title', 'description'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this._rendered = false;
}
connectedCallback() {
this._render();
}
attributeChangedCallback() {
if (this._rendered) {
this._render();
}
}
_render() {
this._rendered = true;
const alt = this.getAttribute('image-alt') || '';
const title = this.getAttribute('title') || '';
const description = this.getAttribute('description') || '';
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
.content-box {
background-color: var(--background-accent-clr, #324f4f);
margin: 50px 20px 20px;
padding: 20px;
border-radius: 20px;
}
.content-box p {
margin: 0;
}
.intro-text {
font-weight: bolder;
font-size: 28px;
color: var(--green-clr, #6ede9a);
}
.project-thumb {
width: 150px;
height: 150px;
object-fit: cover;
margin-right: 15px;
border-radius: 75px;
float: left;
}
::slotted(p) { margin: 0; }
</style>
<div class="content-box">
<img class="project-thumb" src="${this._escapeAttribute(this.getAttribute('image') || '')}" alt="${this._escapeAttribute(alt)}">
<p><span class="intro-text"></span><slot></slot></p>
</div>`;
this.shadowRoot.querySelector('.intro-text').textContent = title;
this._renderDescription(description);
}
_renderDescription(description) {
const slot = this.shadowRoot.querySelector('slot');
slot.textContent = '';
const linkPattern = /\[\[([^|\]]+)\|([^\]]+)\]\]/g;
let lastIndex = 0;
let match;
while ((match = linkPattern.exec(description)) !== null) {
if (match.index > lastIndex) {
slot.appendChild(document.createTextNode(description.slice(lastIndex, match.index)));
}
const link = document.createElement('a');
link.href = match[2];
link.textContent = match[1];
if (match[2].startsWith('http')) {
link.target = '_blank';
link.rel = 'noopener';
}
slot.appendChild(link);
lastIndex = match.index + match[0].length;
if (linkPattern.lastIndex === match.index) {
linkPattern.lastIndex++;
}
}
if (lastIndex < description.length) {
slot.appendChild(document.createTextNode(description.slice(lastIndex)));
}
}
_escapeAttribute(value) {
return value
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;');
}
}
customElements.define('project-card', ProjectCard);
Binary file not shown.
Binary file not shown.