Skip to content

Commit 1f44828

Browse files
committed
Buscador hecho
1 parent af00185 commit 1f44828

8 files changed

Lines changed: 242 additions & 33 deletions

File tree

src/components/Navbar.astro

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
// Navbar.astro
3+
const { posts } = Astro.props;
4+
---
5+
6+
<nav class="nav">
7+
<a href="/astro-proyect/"><img src="/astro-proyect/images/logo_TB_horiz_negativo-01.png" alt="The_bridge" class="logo"></a>
8+
9+
<div class="search-container">
10+
<input
11+
type="text"
12+
id="search-input"
13+
placeholder="Buscar..."
14+
aria-label="Buscar"
15+
class="search-input"
16+
style="padding: 0.5rem; border-radius: 0.25rem; border: 1px solid #ccc;"
17+
/>
18+
<ul id="search-results" class="search-dropdown"></ul>
19+
</div>
20+
21+
<ul class="navList">
22+
<li class="navItem"><a href="/astro-proyect/fundamentals/">Fundamentals</a></li>
23+
<li class="navItem"><a href="/astro-proyect/backend/">BackEnd</a></li>
24+
<li class="navItem"><a href="/astro-proyect/frontend/">FrontEnd</a></li>
25+
</ul>
26+
27+
<button class="hamburger" aria-label="Toggle menu">&#9776;</button>
28+
</nav>
29+
30+
<script type="module">
31+
let posts = [];
32+
const sectionMap = {
33+
html: 'fundamentals',
34+
css: 'fundamentals',
35+
javascript: 'fundamentals',
36+
react: 'frontend',
37+
nodejs: 'backend',
38+
bases_de_datos: 'backend',
39+
};
40+
41+
async function loadSearchData() {
42+
if (posts.length > 0) return; // Evita recargar si ya están
43+
const res = await fetch('/astro-proyect/search-index.json');
44+
const data = await res.json();
45+
46+
const sectionPosts = Object.entries(sectionMap).map(([category, section]) => ({
47+
title: category,
48+
description: `Ver todos los artículos de ${category}`,
49+
url: `/astro-proyect/${section}/${category}/`
50+
}));
51+
52+
const contentPosts = data.map(post => ({
53+
title: post.title,
54+
description: post.description,
55+
url: `/astro-proyect/${post.slug}`
56+
}));
57+
58+
posts = [...sectionPosts, ...contentPosts];
59+
}
60+
61+
function buscar(term) {
62+
const input = term.toLowerCase();
63+
const resultsBox = document.querySelector("#search-results");
64+
65+
if (!input) {
66+
resultsBox.innerHTML = '';
67+
return;
68+
}
69+
70+
const results = posts.filter(post =>
71+
post.title.toLowerCase().includes(input) ||
72+
post.description.toLowerCase().includes(input)
73+
);
74+
75+
if (results.length === 0) {
76+
resultsBox.innerHTML = '<li style="padding: 0.75rem 1rem; color: white;">No se encontraron resultados</li>';
77+
return;
78+
}
79+
80+
resultsBox.innerHTML = results.map(post => `
81+
<li class="search-result-item">
82+
<a href="${post.url}">
83+
<strong>${post.title}</strong><br>
84+
<span>${post.description}</span>
85+
</a>
86+
</li>
87+
`).join('');
88+
}
89+
90+
function initSearch() {
91+
const inputEl = document.querySelector("#search-input");
92+
if (inputEl) {
93+
inputEl.addEventListener("input", (e) => buscar(e.target.value));
94+
}
95+
96+
document.addEventListener("click", (e) => {
97+
const container = document.querySelector(".search-container");
98+
if (!container.contains(e.target)) {
99+
document.querySelector("#search-results").innerHTML = "";
100+
}
101+
});
102+
103+
document.addEventListener("keydown", (e) => {
104+
if (e.key === "Escape") {
105+
document.querySelector("#search-results").innerHTML = "";
106+
document.getElementById("search-input").value = "";
107+
}
108+
});
109+
}
110+
111+
// Inicializa en carga inicial
112+
document.addEventListener("DOMContentLoaded", async () => {
113+
await loadSearchData();
114+
initSearch();
115+
116+
document.addEventListener('astro:after-swap', () => {
117+
initSearch();
118+
})
119+
});
120+
</script>
121+

src/layouts/Layout.astro

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
---
22
import { ViewTransitions } from 'astro:transitions';
33
import { Breadcrumbs } from "astro-breadcrumbs";
4+
import { getCollection } from 'astro:content';
45
import "astro-breadcrumbs/breadcrumbs.scss"
56
import "../styles/custom-breadcrumbs.scss"
67
import CodeEditor from '../components/CodeEditor.astro'
78
import Modal from '../components/Modal.astro'
9+
import Navbar from '../components/Navbar.astro';
810
import '../styles/global.css'
911
12+
const allPosts = [
13+
...(await getCollection('javascript')),
14+
...(await getCollection('html')),
15+
...(await getCollection('css')),
16+
...(await getCollection('bases_de_datos')),
17+
...(await getCollection('nodejs')),
18+
...(await getCollection('react')),
19+
];
20+
1021
1122
let currentPath = Astro.url.pathname;
1223
@@ -36,22 +47,7 @@ const { title } = Astro.props;
3647
</head>
3748
<body>
3849
<header>
39-
<nav class="nav">
40-
<a href="/astro-proyect/"><img src="/astro-proyect/images/logo_TB_horiz_negativo-01.png" alt="The_bridge" class="logo"></a>
41-
<!--<form id="search-form">
42-
<input type="text" id="search-input" placeholder="Buscar..." aria-label="Buscar" />
43-
<button type="submit">Buscar</button>
44-
</form> -->
45-
<div id="search-results"></div>
46-
<ul class="navList">
47-
<li class="navItem"><a href="/astro-proyect/fundamentals/">Fundamentals</a></li>
48-
<li class="navItem"><a href="/astro-proyect/backend/">BackEnd</a></li>
49-
<li class="navItem"><a href="/astro-proyect/frontend/">FrontEnd</a></li>
50-
</ul>
51-
<button class="hamburger" aria-label="Toggle menu">
52-
&#9776;
53-
</button>
54-
</nav>
50+
<Navbar posts={allPosts}/>
5551
</header>
5652
<div class="back-breadcrumbs">
5753
{isRoot ? "" :
@@ -79,18 +75,5 @@ const { title } = Astro.props;
7975
<Modal>
8076
<CodeEditor/>
8177
</Modal>
82-
83-
<script>
84-
document.addEventListener('DOMContentLoaded', function () {
85-
const hamburger = document.querySelector('.hamburger');
86-
const nav = document.querySelector('.nav');
87-
88-
if (hamburger && nav) { // Verificamos que ambos elementos existan
89-
hamburger.addEventListener('click', function () {
90-
nav.classList.toggle('active'); // Activa/desactiva la clase 'active'
91-
});
92-
}
93-
});
94-
</script>
9578
</body>
9679
</html>
File renamed without changes.
File renamed without changes.

src/pages/backend/index.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ let currentPath = Astro.url.pathname;
1111
</div>
1212
<ul role="list" class="link-card-grid">
1313
<Card
14-
href=`${currentPath}bases-de-datos/`
14+
href=`${currentPath}bases_de_datos/`
1515
title="Bases de Datos"
1616
description="Descripción de Bases de Datos"
1717
/>

src/pages/fundamentals/javascript/index.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const posts = (await getCollection('javascript')).sort(
1111
<Layout title="The Bridge">
1212
<section>
1313
<div class="pageTitle">
14-
<h1>HTML</h1>
14+
<h1>Javascript</h1>
1515
<img src="/astro-proyect/images/filled_icon.svg" alt="logo_programacion" class="logo_codigo">
1616
</div>
1717
<ul role="list" class="link-card-grid">

src/pages/search-index.json.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { getCollection } from 'astro:content';
2+
3+
/** @type {import('astro').APIRoute} */
4+
export async function GET() {
5+
const javascript = await getCollection('javascript');
6+
const html = await getCollection('html');
7+
const css = await getCollection('css');
8+
const bases_de_datos = await getCollection('bases_de_datos');
9+
const nodejs = await getCollection('nodejs');
10+
const react = await getCollection('react');
11+
12+
// Función que añade el prefijo correcto según la colección
13+
function mapWithPrefix(items, prefix) {
14+
return items.map((item) => ({
15+
title: item.data.title,
16+
description: item.data.description,
17+
slug: `${prefix}/${item.collection}/${item.slug}/`,
18+
}));
19+
}
20+
21+
const allPosts = [
22+
...mapWithPrefix(javascript, 'fundamentals'),
23+
...mapWithPrefix(html, 'fundamentals'),
24+
...mapWithPrefix(css, 'fundamentals'),
25+
...mapWithPrefix(bases_de_datos, 'backend'),
26+
...mapWithPrefix(nodejs, 'backend'),
27+
...mapWithPrefix(react, 'frontend'),
28+
];
29+
30+
return new Response(JSON.stringify(allPosts), {
31+
status: 200,
32+
headers: {
33+
'Content-Type': 'application/json',
34+
},
35+
});
36+
}

src/styles/global.css

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,70 @@ h4 {
7373
display: none;
7474
}
7575

76+
/**************** Buscador ********************/
77+
78+
.search-container {
79+
position: relative;
80+
width: 250px;
81+
}
82+
83+
.search-input {
84+
width: 100%;
85+
padding: 0.5rem;
86+
border-radius: 4px;
87+
border: 1px solid #ccc;
88+
}
89+
90+
.search-dropdown {
91+
position: absolute;
92+
top: 2.5rem;
93+
left: 0;
94+
right: 0;
95+
background: #2F2F2F;
96+
z-index: 100;
97+
border-radius: 4px;
98+
list-style: none;
99+
padding: 0;
100+
margin: 0;
101+
border: 2px solid rgba(255, 255, 255, 0.1);
102+
box-shadow: 0 10px 10px rgba(0,0,0,0.4);
103+
overflow: hidden;
104+
max-height: 300px;
105+
overflow-y: auto;
106+
}
107+
108+
.search-dropdown li {
109+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
110+
}
111+
112+
.search-dropdown li:last-child {
113+
border-bottom: none;
114+
}
115+
116+
.search-dropdown li a {
117+
display: block;
118+
padding: 0.75rem 1rem;
119+
text-decoration: none; /* 🔧 esto quita el subrayado */
120+
color: white;
121+
font-size: 1rem;
122+
background-color: #232323;
123+
transition: background-color 0.2s ease-in-out;
124+
}
125+
126+
.search-dropdown li a:hover {
127+
background-color: #2F2F2F;
128+
color: #EF3340;
129+
}
130+
131+
.search-dropdown:empty {
132+
display: none;
133+
}
134+
76135
@media screen and (max-width: 768px) {
136+
.nav {
137+
flex-direction: column;
138+
}
139+
77140
.navList {
78141
display: none;
79142
flex-direction: column;
@@ -100,13 +163,17 @@ h4 {
100163
padding: 0;
101164
}
102165

103-
.nav.active .navList {
166+
.nav.active .navList .search-container {
104167
display: flex;
105168
max-height: 300px;
106169
max-width: max-content;
107170
padding: 1rem;
108171
}
109172

173+
.search-container {
174+
order: 2;
175+
}
176+
110177
}
111178

112179
.back-breadcrumbs {
@@ -176,6 +243,8 @@ pre {
176243
word-wrap: break-word;
177244
width: 465px;
178245
height: 468px;
246+
overflow: scroll;
247+
179248
}
180249
code {
181250
font-family: 'Consolas', 'Roboto', sans-serif;
@@ -301,7 +370,7 @@ p {
301370
right: 10px;
302371
}
303372

304-
/********* MODAL *************/
373+
/********* Modal *************/
305374

306375
dialog::backdrop {
307376
background-color: rgba(0, 0, 0, 0.5);

0 commit comments

Comments
 (0)