oldmonk69 commited on
Commit
9a50734
·
verified ·
1 Parent(s): b7c4ad1

Delete script.js

Browse files
Files changed (1) hide show
  1. script.js +0 -143
script.js DELETED
@@ -1,143 +0,0 @@
1
- /* =========================================================
2
- # File: script.js
3
- # Adds: theme toggle, mobile menu, hash routing, scroll spy,
4
- # slider, filters, lightbox, form validation.
5
- # ========================================================= */
6
-
7
- (function () {
8
- const $ = (sel, root = document) => root.querySelector(sel);
9
- const $$ = (sel, root = document) => [...root.querySelectorAll(sel)];
10
-
11
- // Theme
12
- $('#themeToggle')?.addEventListener('click', () => {
13
- const root = document.documentElement;
14
- const willDark = !root.classList.contains('dark');
15
- root.classList.toggle('dark', willDark);
16
- localStorage.setItem('nnai-theme', willDark ? 'dark' : 'light');
17
- });
18
-
19
- // Mobile menu
20
- const menuBtn = $('#menuBtn');
21
- const mobileMenu = $('#mobileMenu');
22
- menuBtn?.addEventListener('click', () => {
23
- const open = !mobileMenu.classList.contains('hidden');
24
- mobileMenu.classList.toggle('hidden', open);
25
- menuBtn.setAttribute('aria-expanded', String(!open));
26
- });
27
- mobileMenu?.addEventListener('click', (e) => {
28
- const link = e.target.closest('[data-route]');
29
- if (link) {
30
- mobileMenu.classList.add('hidden');
31
- menuBtn.setAttribute('aria-expanded', 'false');
32
- }
33
- });
34
-
35
- // Routing
36
- function goTo(hash) {
37
- const id = (hash || '#home').replace('#','');
38
- const el = document.getElementById(id);
39
- if (!el) return;
40
- if (location.hash !== '#' + id) history.pushState({ id }, '', '#' + id);
41
- el.scrollIntoView({ behavior: 'smooth', block: 'start' });
42
- }
43
- document.addEventListener('click', (e) => {
44
- const a = e.target.closest('a[data-route]');
45
- if (!a) return;
46
- const href = a.getAttribute('href');
47
- if (href?.startsWith('#')) {
48
- e.preventDefault(); goTo(href);
49
- }
50
- });
51
- window.addEventListener('popstate', (e) => {
52
- const id = (e.state && e.state.id) || (location.hash.replace('#','') || 'home');
53
- document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
54
- });
55
- window.addEventListener('load', () => goTo(location.hash || '#home'));
56
-
57
- // Scroll spy
58
- const sections = $$('.section');
59
- const navLinks = $$('.nav-link');
60
- const spy = new IntersectionObserver((entries) => {
61
- entries.forEach((entry) => {
62
- const id = entry.target.id;
63
- const link = navLinks.find((a) => a.getAttribute('href') === '#' + id);
64
- if (!link) return;
65
- if (entry.isIntersecting) { navLinks.forEach(l => l.classList.remove('active')); link.classList.add('active'); }
66
- });
67
- }, { rootMargin: '-40% 0px -55% 0px', threshold: 0.01 });
68
- sections.forEach((s) => spy.observe(s));
69
-
70
- // Slider (simple, accessible)
71
- const slides = $$('.slide');
72
- let idx = slides.findIndex(s => s.classList.contains('is-active'));
73
- if (idx < 0) idx = 0, slides[0]?.classList.add('is-active');
74
- function show(i) {
75
- if (!slides.length) return;
76
- slides[idx]?.classList.remove('is-active');
77
- idx = (i + slides.length) % slides.length;
78
- slides[idx]?.classList.add('is-active');
79
- }
80
- $('.slider-btn.prev')?.addEventListener('click', () => show(idx - 1));
81
- $('.slider-btn.next')?.addEventListener('click', () => show(idx + 1));
82
- let auto = setInterval(() => show(idx + 1), 6000);
83
- // Pause on hover/focus
84
- const slider = $('.slider');
85
- slider?.addEventListener('mouseenter', () => clearInterval(auto));
86
- slider?.addEventListener('mouseleave', () => auto = setInterval(() => show(idx + 1), 6000));
87
-
88
- // Portfolio filter
89
- const grid = $('#portfolioGrid');
90
- const filterButtons = $$('.filter-chip');
91
- filterButtons.forEach((btn) => {
92
- btn.addEventListener('click', () => {
93
- filterButtons.forEach((b) => b.classList.remove('active'));
94
- btn.classList.add('active');
95
- const f = btn.dataset.filter;
96
- $$('.portfolio-card', grid).forEach((card) => {
97
- card.style.display = (f === '*' || card.dataset.cat === f) ? '' : 'none';
98
- });
99
- });
100
- });
101
-
102
- // Lightbox
103
- const dlg = $('#lightbox');
104
- const dlgImg = $('#lightboxImg');
105
- const dlgClose = $('#lightboxClose');
106
- function openLightbox(url) {
107
- dlgImg.src = url;
108
- if (typeof dlg.showModal === 'function') dlg.showModal();
109
- else dlg.setAttribute('open','true');
110
- }
111
- function closeLightbox() {
112
- dlgImg.src = '';
113
- if (typeof dlg.close === 'function') dlg.close();
114
- else dlg.removeAttribute('open');
115
- }
116
- document.addEventListener('click', (e) => {
117
- const card = e.target.closest('[data-lightbox]');
118
- if (!card) return;
119
- e.preventDefault(); openLightbox(card.dataset.lightbox);
120
- });
121
- dlgClose?.addEventListener('click', closeLightbox);
122
- dlg?.addEventListener('click', (e) => {
123
- const rect = dlgImg.getBoundingClientRect();
124
- const inside = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
125
- if (!inside) closeLightbox();
126
- });
127
- document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && dlg?.open) closeLightbox(); });
128
-
129
- // Contact form validation
130
- const form = $('#contactForm');
131
- const formMsg = $('#formMsg');
132
- form?.addEventListener('submit', (e) => {
133
- if (!form.checkValidity()) {
134
- e.preventDefault();
135
- formMsg.textContent = '❗ Please complete all required fields correctly.';
136
- formMsg.className = 'text-sm text-red-600 dark:text-red-400';
137
- return;
138
- }
139
- formMsg.textContent = '✔️ Sending...';
140
- formMsg.className = 'text-sm text-slate-600 dark:text-slate-300';
141
- });
142
-
143
- })();