Skip to content

Commit c24ce43

Browse files
committed
..
1 parent b1b4569 commit c24ce43

File tree

6 files changed

+208
-138
lines changed

6 files changed

+208
-138
lines changed

source/_assets/css/app.css

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,49 @@ body {
168168
}
169169
}
170170

171+
/* Header scroll state - Vanilla JS controlled */
172+
header.scrolled #header-container {
173+
padding-left: 1rem;
174+
padding-right: 1rem;
175+
}
176+
177+
@media (min-width: 768px) {
178+
header.scrolled #header-container {
179+
padding-left: 1.5rem;
180+
padding-right: 1.5rem;
181+
}
182+
}
183+
184+
header.scrolled #header-inner {
185+
background-color: rgba(255, 255, 255, 0.95) !important;
186+
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1) !important;
187+
max-width: 64rem !important;
188+
padding-left: 1.5rem !important;
189+
padding-right: 1.5rem !important;
190+
border-color: rgba(229, 231, 235, 0.7) !important;
191+
}
192+
193+
.dark header.scrolled #header-inner {
194+
background-color: rgba(17, 24, 39, 0.95) !important;
195+
border-color: rgba(55, 65, 81, 0.7) !important;
196+
}
197+
198+
/* Logo size change on scroll */
199+
header.scrolled #logo-text {
200+
font-size: 1rem; /* text-base */
201+
}
202+
203+
@media (min-width: 640px) {
204+
header.scrolled #logo-text {
205+
font-size: 1.125rem; /* sm:text-lg */
206+
}
207+
}
208+
209+
/* Show divider when scrolled */
210+
header.scrolled #header-divider {
211+
opacity: 1;
212+
}
213+
171214
/* Custom Scrollbar - Sleek & Minimal */
172215
::-webkit-scrollbar {
173216
width: 8px;

source/_assets/js/app.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import bash from "highlight.js/lib/languages/bash";
66
import Alpine from "alpinejs";
77
import intersect from '@alpinejs/intersect';
88
import persist from '@alpinejs/persist';
9+
import './scroll-handler.js';
910

1011
window.axios = axios;
1112
window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Ultra-performant scroll handler - No Alpine, No RAF, No timers, No forEach
2+
// Direct DOM manipulation with passive listeners
3+
4+
let lastScrollY = 0;
5+
let ticking = false;
6+
7+
// Cache DOM elements
8+
let header = null;
9+
let scrollButton = null;
10+
let scrollUpArrow = null;
11+
let scrollDownArrow = null;
12+
let progressBar = null;
13+
let progressBarContainer = null;
14+
15+
// Initialize scroll handler
16+
function initScrollHandler() {
17+
// Cache all DOM elements once
18+
header = document.querySelector('header[data-scroll-header]');
19+
scrollButton = document.getElementById('scroll-button');
20+
scrollUpArrow = document.getElementById('scroll-up-arrow');
21+
scrollDownArrow = document.getElementById('scroll-down-arrow');
22+
progressBar = document.getElementById('scroll-progress-bar');
23+
progressBarContainer = document.getElementById('scroll-progress-container');
24+
25+
// Set initial states
26+
updateScrollState();
27+
28+
// Single passive scroll listener
29+
window.addEventListener('scroll', onScroll, { passive: true });
30+
}
31+
32+
function onScroll() {
33+
if (ticking) return;
34+
ticking = true;
35+
36+
// Use native browser scheduling (not RAF - just next tick)
37+
Promise.resolve().then(() => {
38+
updateScrollState();
39+
ticking = false;
40+
});
41+
}
42+
43+
function updateScrollState() {
44+
const scrollY = window.pageYOffset;
45+
const docHeight = document.documentElement.scrollHeight;
46+
const winHeight = window.innerHeight;
47+
const maxScroll = docHeight - winHeight;
48+
const scrollPercent = maxScroll > 0 ? (scrollY / maxScroll) * 100 : 0;
49+
50+
// 1. Update header (scrolled state)
51+
if (header) {
52+
if (scrollY > 20) {
53+
if (!header.classList.contains('scrolled')) {
54+
header.classList.add('scrolled');
55+
}
56+
} else {
57+
if (header.classList.contains('scrolled')) {
58+
header.classList.remove('scrolled');
59+
}
60+
}
61+
}
62+
63+
// 2. Update scroll button visibility & direction
64+
if (scrollButton && scrollUpArrow && scrollDownArrow) {
65+
const isAtTop = scrollY < 100;
66+
const isAtBottom = scrollPercent > 95;
67+
68+
// Show/hide button
69+
if (isAtTop || isAtBottom || (scrollY > 100 && scrollPercent < 95)) {
70+
if (scrollButton.style.display === 'none') {
71+
scrollButton.style.display = 'block';
72+
}
73+
} else {
74+
if (scrollButton.style.display !== 'none') {
75+
scrollButton.style.display = 'none';
76+
}
77+
}
78+
79+
// Direction
80+
if (isAtTop || (!isAtBottom && scrollY > lastScrollY)) {
81+
// Scrolling down or at top = show down arrow
82+
if (scrollDownArrow.style.display !== 'block') {
83+
scrollDownArrow.style.display = 'block';
84+
scrollUpArrow.style.display = 'none';
85+
}
86+
} else {
87+
// Scrolling up or at bottom = show up arrow
88+
if (scrollUpArrow.style.display !== 'block') {
89+
scrollUpArrow.style.display = 'block';
90+
scrollDownArrow.style.display = 'none';
91+
}
92+
}
93+
}
94+
95+
// 3. Update progress bar
96+
if (progressBar && progressBarContainer) {
97+
if (scrollPercent > 5) {
98+
if (progressBarContainer.style.display === 'none') {
99+
progressBarContainer.style.display = 'block';
100+
}
101+
progressBar.style.width = scrollPercent + '%';
102+
} else {
103+
if (progressBarContainer.style.display !== 'none') {
104+
progressBarContainer.style.display = 'none';
105+
}
106+
}
107+
}
108+
109+
lastScrollY = scrollY;
110+
}
111+
112+
// Initialize on DOM ready
113+
if (document.readyState === 'loading') {
114+
document.addEventListener('DOMContentLoaded', initScrollHandler);
115+
} else {
116+
initScrollHandler();
117+
}
118+
119+
// Export for button click handlers
120+
window.scrollToTop = () => {
121+
window.scrollTo({ top: 0, behavior: 'smooth' });
122+
};
123+
124+
window.scrollToBottom = () => {
125+
window.scrollTo({ top: document.documentElement.scrollHeight, behavior: 'smooth' });
126+
};

source/_layouts/layout.blade.php

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,18 @@ class="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z
5858
</a>
5959

6060
{{-- Modern Floating Header --}}
61-
<header x-data="{ mobileMenuOpen: false, scrolled: false }"
62-
@scroll.window="scrolled = (window.pageYOffset > 20)"
61+
<header x-data="{ mobileMenuOpen: false }"
6362
@click.away="mobileMenuOpen = false"
63+
data-scroll-header
6464
class="fixed top-0 w-full z-50 py-3 md:py-4">
65-
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-6 lg:px-8 transition-[padding] duration-300"
66-
:class="{ 'md:px-4 lg:px-6': scrolled }">
67-
<div class="relative mx-auto transition-[background-color,box-shadow,max-width,padding,border-color] duration-300 ease-out bg-white/95 dark:bg-gray-900/95 shadow-md rounded-2xl max-w-6xl px-4 sm:px-6 py-2 border border-gray-200/50 dark:border-gray-800/50 md:bg-transparent md:shadow-none md:border-transparent"
68-
:class="{
69-
'!bg-white/95 dark:!bg-gray-900/95 !shadow-lg !max-w-5xl !px-6 !border-gray-200/70 dark:!border-gray-700/70': scrolled
70-
}">
65+
<div id="header-container" class="max-w-7xl mx-auto px-4 sm:px-6 md:px-6 lg:px-8 transition-[padding] duration-300">
66+
<div id="header-inner" class="relative mx-auto transition-[background-color,box-shadow,max-width,padding,border-color] duration-300 ease-out bg-white/95 dark:bg-gray-900/95 shadow-md rounded-2xl max-w-6xl px-4 sm:px-6 py-2 border border-gray-200/50 dark:border-gray-800/50 md:bg-transparent md:shadow-none md:border-transparent">
7167
<div class="flex justify-between items-center h-10 sm:h-12">
7268
{{-- Logo --}}
7369
<div class="flex items-center">
7470
<a href="{{ $page->localUrl('/') }}" class="flex items-center space-x-2 group">
7571
<img src="{{ $page->baseUrl }}/assets/images/logo.png" class="w-7 h-7 sm:w-8 sm:h-8 transition-transform duration-500 group-hover:rotate-12" alt="Awssat" aria-roledescription="Logo of Awssat">
76-
<span class="text-lg sm:text-xl font-bold tracking-tight text-gray-900 dark:text-white"
77-
:class="{ 'text-base sm:text-lg': scrolled }">Awssat</span>
72+
<span id="logo-text" class="text-lg sm:text-xl font-bold tracking-tight text-gray-900 dark:text-white">Awssat</span>
7873
</a>
7974
</div>
8075

@@ -99,7 +94,7 @@ class="relative px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-300
9994
<span class="absolute inset-x-0 bottom-0 h-0.5 bg-primary-500 transform scale-x-0 group-hover:scale-x-100 transition-transform origin-left"></span>
10095
</a>
10196

102-
<div class="h-6 w-px bg-gray-200 dark:bg-gray-700 mx-4" :class="{ 'opacity-0': !scrolled }"></div>
97+
<div id="header-divider" class="h-6 w-px bg-gray-200 dark:bg-gray-700 mx-4 opacity-0"></div>
10398

10499
{{-- Dark Mode Toggle --}}
105100
<div class="flex items-center">

source/_layouts/partial/home_content.blade.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@
1919
{{-- Base Gradient --}}
2020
<div class="absolute inset-0 bg-gray-50 dark:bg-[#030712]"></div>
2121

22-
{{-- Animated Orbs --}}
23-
<div class="absolute top-[-20%] left-[-10%] w-[500px] h-[500px] rounded-full bg-purple-500/20 blur-[60px] mix-blend-multiply dark:mix-blend-screen animate-blob motion-reduce:animate-none motion-reduce:opacity-30"></div>
24-
<div class="absolute top-[-10%] right-[-10%] w-[500px] h-[500px] rounded-full bg-cyan-500/20 blur-[60px] mix-blend-multiply dark:mix-blend-screen animate-blob animation-delay-2000 motion-reduce:animate-none motion-reduce:opacity-30"></div>
22+
{{-- Orbs --}}
23+
<div class="absolute top-[-20%] left-[-10%] w-[500px] h-[500px] rounded-full bg-purple-500/20 blur-[60px] mix-blend-multiply dark:mix-blend-screen animate-none motion-reduce:opacity-30"></div>
24+
<div class="absolute top-[-10%] right-[-10%] w-[500px] h-[500px] rounded-full bg-cyan-500/20 blur-[60px] mix-blend-multiply dark:mix-blend-screen animate-none motion-reduce:opacity-30"></div>
2525

2626

2727
<div class="absolute inset-0" style="background-image: radial-gradient(rgba(120, 119, 198, 0.3) 1px, transparent 1px); background-size: 40px 40px; opacity: 0.1;"></div>
2828
</div>
2929

3030
{{-- Main Hero Logo (Central, Large, Nice Gradient) --}}
3131
<div class="absolute inset-0 flex items-center justify-center overflow-hidden pointer-events-none select-none z-0">
32-
<svg class="w-[280px] h-[280px] sm:w-[500px] sm:h-[500px] md:w-[700px] md:h-[700px] lg:w-[900px] lg:h-[900px] opacity-10 dark:opacity-5 animate-float-gentle" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
32+
<svg class="w-[280px] h-[280px] sm:w-[500px] sm:h-[500px] md:w-[700px] md:h-[700px] lg:w-[900px] lg:h-[900px] opacity-10 dark:opacity-5 animate-none" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
3333
<defs>
3434
<linearGradient id="heroGradient" x1="0%" y1="0%" x2="100%" y2="100%">
3535
<stop offset="0%" style="stop-color: #8b5cf6" /> {{-- Purple --}}
@@ -61,7 +61,7 @@
6161

6262

6363
{{-- Animated Badge --}}
64-
<div class="inline-flex items-center gap-2 px-4 py-2 mb-8 rounded-full bg-white/80 dark:bg-gray-900/80 backdrop-blur-md border border-gray-200 dark:border-gray-800 shadow-sm hover:shadow-md transition-all duration-300 animate-fade-in-up">
64+
<div class="inline-flex items-center gap-2 px-4 py-2 mb-8 rounded-full bg-white/80 dark:bg-gray-900/80 border border-gray-200 dark:border-gray-800 shadow-sm hover:shadow-md transition-all duration-300 animate-fade-in-up">
6565
<span class="relative flex w-2.5 h-2.5">
6666
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
6767
<span class="relative inline-flex rounded-full h-2.5 w-2.5 bg-green-500"></span>
@@ -121,7 +121,7 @@
121121
</section>
122122

123123
{{-- The Authority Grid (Story-driven Bento) --}}
124-
<section class="py-32 px-4 relative z-10 bg-white/60 dark:bg-gray-900/60 backdrop-blur-xl border-t border-gray-200/50 dark:border-gray-800/50">
124+
<section class="py-32 px-4 relative z-10 bg-white/60 dark:bg-gray-900/60 border-t border-gray-200/50 dark:border-gray-800/50">
125125
<div class="container mx-auto max-w-7xl">
126126
<div class="text-center mb-24 animate-on-scroll">
127127
<h2 class="text-4xl md:text-6xl font-black mb-6 tracking-tight bg-clip-text text-transparent bg-gradient-to-b from-gray-900 to-gray-600 dark:from-white dark:to-gray-400">
@@ -692,7 +692,7 @@
692692
{{-- Bottom Nav --}}
693693

694694

695-
<div class="flex-none absolute bottom-0 left-0 right-0 rounded-b-[2rem] overflow-hidden h-8 bg-gray-900/90 backdrop-blur-md border-t border-gray-800 flex justify-around items-center px-6">
695+
<div class="flex-none absolute bottom-0 left-0 right-0 rounded-b-[2rem] overflow-hidden h-8 bg-gray-900/90 border-t border-gray-800 flex justify-around items-center px-6">
696696

697697

698698

@@ -960,7 +960,7 @@
960960

961961
<div class="absolute inset-0 flex items-center justify-center">
962962

963-
<div class="w-20 h-20 bg-amber-500/10 rounded-full flex items-center justify-center backdrop-blur-sm border border-amber-500/20">
963+
<div class="w-20 h-20 bg-amber-500/10 rounded-full flex items-center justify-center border border-amber-500/20">
964964

965965
<svg class="w-10 h-10 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg>
966966

@@ -1156,7 +1156,7 @@
11561156
@if($item->tech_stack)
11571157
<div class="flex flex-wrap gap-2">
11581158
@foreach(array_slice($item->tech_stack, 0, 3) as $tech)
1159-
<span class="px-2 py-1 rounded-md bg-white/20 text-white text-xs backdrop-blur-sm">
1159+
<span class="px-2 py-1 rounded-md bg-white/20 text-white text-xs">
11601160
{{ $tech }}
11611161
</span>
11621162
@endforeach

0 commit comments

Comments
 (0)