PageSourceSearch

https://aala.ai/scripts/liquid-glass.js

js aala.ai collected 2026-10-05 12:23:32 UTC 7,089 bytes, 195 lines download raw bytes

1// Liquid Glass Effect - Clean CodePen Implementation
2class LiquidGlass {
3    constructor() {
4        this.init();
5    }
6
7    init() {
8        this.applyEffect();
9    }
10
11    applyEffect() {
12        const header = document.querySelector('header, .navbar');
13        const mobileNav = document.querySelector('.mobile-nav');
14        
15        if (header) {
16            // Add glass container class to header
17            header.classList.add('glass-container');
18
19            // Only add glass layers if not already present
20            if (!header.querySelector('.glass-filter')) {
21                const glassHTML = `
22                    <div class="glass-filter"></div>
23                    <div class="glass-overlay"></div>
24                    <div class="glass-specular"></div>
25                `;
26                header.insertAdjacentHTML('afterbegin', glassHTML);
27            }
28
29            // Ensure container has glass-content class
30            const container = header.querySelector('.container');
31            if (container) {
32                container.classList.add('glass-content');
33            }
34        }
35        
36        // Add the SVG filter to body (needs to be available for all glass effects)
37        if (!document.querySelector('#lensFilter')) {
38            const svgFilter = `
39                <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
40                    <defs>
41                        <filter id="lensFilter" x="-50%" y="-50%" width="200%" height="200%">
42                            <!-- Create turbulence for displacement -->
43                            <feTurbulence type="fractalNoise" baseFrequency="0.02 0.03" numOctaves="3" result="turbulence" seed="2" />
44                            
45                            <!-- Convert turbulence to alpha -->
46                            <feColorMatrix in="turbulence" mode="saturate" values="5" result="colormatrix" />
47                            
48                            <!-- Blur for smooth displacement -->
49                            <feGaussianBlur in="colormatrix" stdDeviation="4" result="blur" />
50                            
51                            <!-- Apply displacement -->
52                            <feDisplacementMap in="SourceGraphic" in2="blur" scale="100" xChannelSelector="R" yChannelSelector="G" result="displaced" />
53                            
54                            <!-- Merge with original for subtle effect -->
55                            <feComposite in="displaced" in2="SourceGraphic" operator="over" />
56                        </filter>
57                    </defs>
58                </svg>
59            `;
60            document.body.insertAdjacentHTML('beforeend', svgFilter);
61        }
62        
63        // Add glass layers to mobile nav too
64        if (mobileNav) {
65            mobileNav.classList.add('glass-mobile');
66            
67            // Only add glass layers if not already added
68            if (!mobileNav.querySelector('.glass-filter')) {
69                const mobileGlassHTML = `
70                    <div class="glass-filter"></div>
71                    <div class="glass-overlay"></div>
72                    <div class="glass-specular"></div>
73                `;
74                mobileNav.insertAdjacentHTML('afterbegin', mobileGlassHTML);
75            }
76        }
77
78        // Add the CSS
79        this.injectStyles();
80    }
81
82    injectStyles() {
83        if (document.querySelector('#liquid-glass-styles')) return;
84
85        const style = document.createElement('style');
86        style.id = 'liquid-glass-styles';
87        style.textContent = `
88            :root {
89                --lg-bg-color: #F7FAFC88;  /* Much more transparent */
90                --lg-highlight: rgba(255, 255, 255, 0.9);  /* Subtle highlight */
91                --lg-text: #333333;
92            }
93
94            .glass-container {
95                position: fixed !important;
96                top: 0;
97                left: 0;
98                right: 0;
99                display: flex;
100                align-items: center;
101                /* overflow: hidden; removed to allow mobile menu dropdown */
102                color: var(--lg-text);
103                z-index: 1000;
104            }
105
106            .glass-filter,
107            .glass-overlay,
108            .glass-specular {
109                position: absolute;
110                inset: 0;
111            }
112
113            .glass-filter {
114                z-index: 0;
115                backdrop-filter: blur(10px);
116                filter: url(#lensFilter)  saturate(120%);  /* Removed saturation and brightness */
117            }
118
119            .glass-overlay {
120                z-index: 1;
121                background: var(--lg-bg-color);
122            }
123
124            .glass-specular {
125                z-index: 2;
126                box-shadow: inset 1px 1px 0 var(--lg-highlight),
127                    inset 0 0 10px var(--lg-highlight);
128            }
129
130            .glass-content {
131                position: relative;
132                z-index: 3;
133                display: flex;
134                flex: 1 1 auto;
135                align-items: center;
136                justify-content: space-between;
137            }
138
139            /* Ensure all navbar content stays on top */
140            .navbar .logo,
141            .navbar .mobile-menu-toggle {
142                /* position: relative; removed as it was breaking mobile menu */
143                z-index: 4;
144            }
145            
146            /* nav-links z-index only when inside navbar (desktop) */
147            @media (min-width: 769px) {
148                .navbar .nav-links {
149                    z-index: 4;
150                }
151            }
152            
153            /* Glass layers for mobile nav */
154            .glass-mobile .glass-filter,
155            .glass-mobile .glass-overlay,
156            .glass-mobile .glass-specular {
157                position: absolute;
158                inset: 0;
159                transition: none !important; /* No transition on glass layers */
160            }
161            
162            .glass-mobile .glass-filter {
163                z-index: 0;
164                backdrop-filter: blur(10px);
165                -webkit-backdrop-filter: blur(10px);
166                filter: url(#lensFilter) saturate(120%);
167                transition: none !important;
168            }
169            
170            .glass-mobile .glass-overlay {
171                z-index: 1;
172                background: var(--lg-bg-color);
173            }
174            
175            .glass-mobile .glass-specular {
176                z-index: 2;
177                box-shadow: inset 1px 1px 0 var(--lg-highlight),
178                    inset 0 0 10px var(--lg-highlight);
179            }
180            
181            /* Mobile nav links need higher z-index than glass layers */
182            .glass-mobile a {
183                position: relative;
184                z-index: 3;
185            }
186        `;
187        document.head.appendChild(style);
188    }
189}
190
191// Initialize on every page load (initial + client-side navigation)
192if (!window._liquidGlassListenerAdded) {
193    window._liquidGlassListenerAdded = true;
194    document.addEventListener('astro:page-load', () => new LiquidGlass());
195}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.