Files
travel-website/index.html
2026-07-03 18:01:32 +03:00

712 lines
23 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Index - travel-website</title>
<style>
:root {
--bg-primary: #ffffff;
--bg-secondary: #f5f5f5;
--bg-card: #fafafa;
--text-primary: #1a1a1a;
--text-secondary: #666666;
--border-color: #e0e0e0;
--accent-color: rgb(0, 148, 202);
--accent-gradient: linear-gradient(135deg, rgb(0, 148, 202) 0%, rgb(0, 120, 170) 100%);
--hover-bg: #f0f0f0;
--shadow: rgba(0, 148, 202, 0.1);
--folder-icon: rgb(237, 137, 54);
--file-icon: rgb(0, 148, 202);
}
[data-theme="dark"] {
--bg-primary: #1a1a2e;
--bg-secondary: #16213e;
--bg-card: #0f3460;
--text-primary: #eaeaea;
--text-secondary: #a0a0a0;
--border-color: #404040;
--accent-color: rgb(0, 148, 202);
--accent-gradient: linear-gradient(135deg, rgb(0, 148, 202) 0%, rgb(0, 120, 170) 100%);
--hover-bg: #1e2a3a;
--shadow: rgba(0, 0, 0, 0.3);
--folder-icon: rgb(246, 173, 85);
--file-icon: rgb(0, 148, 202);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
body {
background: var(--bg-primary);
color: var(--text-primary);
min-height: 100vh;
transition: all 0.3s ease;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: var(--bg-secondary);
border-radius: 8px;
box-shadow: 0 2px 8px var(--shadow);
overflow: hidden;
}
.quick-nav-container {
position: relative;
}
.quick-nav-btn {
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 6px;
}
.quick-nav-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.quick-nav-dropdown {
position: absolute;
top: 100%;
left: 0;
margin-top: 8px;
background: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: 8px;
box-shadow: 0 4px 20px var(--shadow);
min-width: 250px;
max-height: 400px;
overflow-y: auto;
display: none;
animation: slideDown 0.2s ease;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.quick-nav-dropdown.active {
display: block;
}
.quick-nav-item {
display: block;
padding: 12px 16px;
color: var(--text-primary);
text-decoration: none;
transition: all 0.2s;
border-bottom: 1px solid var(--border-color);
}
.quick-nav-item:last-child {
border-bottom: none;
}
.quick-nav-item:hover {
background: var(--hover-bg);
padding-left: 20px;
}
header {
background: var(--bg-primary);
padding: 30px;
border-bottom: 1px solid var(--border-color);
}
h1 {
font-size: 1.75rem;
font-weight: 600;
color: var(--text-primary);
cursor: pointer;
transition: all 0.2s;
}
h1:hover {
color: var(--accent-color);
transform: translateX(5px);
}
.breadcrumb {
color: var(--text-secondary);
font-size: 0.9rem;
margin-bottom: 15px;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.breadcrumb a {
color: var(--accent-color);
text-decoration: none;
transition: all 0.2s;
padding: 2px 6px;
border-radius: 4px;
}
.breadcrumb a:hover {
background: var(--hover-bg);
text-decoration: underline;
}
.breadcrumb-separator {
color: var(--text-secondary);
opacity: 0.5;
}
.stats {
display: inline-block;
background: var(--bg-card);
padding: 8px 16px;
border-radius: 4px;
font-size: 0.85rem;
color: var(--text-secondary);
border: 1px solid var(--border-color);
}
/* ===== SEARCH RESULTS ===== */
.search-results {
margin-top: 20px;
display: none;
}
.search-results.active {
display: block;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.search-results-header {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 15px;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 8px;
}
.search-result-item {
display: flex;
align-items: center;
padding: 12px;
background: var(--bg-primary);
border: 1px solid var(--border-color);
border-radius: 6px;
margin-bottom: 8px;
text-decoration: none;
color: inherit;
transition: all 0.2s;
}
.search-result-item:hover {
background: var(--hover-bg);
transform: translateX(5px);
border-color: var(--accent-color);
}
.search-result-icon {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: var(--bg-secondary);
border-radius: 4px;
margin-right: 12px;
font-size: 1.2rem;
}
.search-result-info {
flex: 1;
}
.search-result-name {
font-weight: 500;
color: var(--text-primary);
margin-bottom: 2px;
}
.search-result-meta {
font-size: 0.8rem;
color: var(--text-secondary);
}
.highlight {
background: rgba(102, 126, 234, 0.2);
padding: 0 2px;
border-radius: 2px;
}
.content {
padding: 30px;
}
.section {
margin-bottom: 40px;
}
.section-title {
font-size: 1.44rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid var(--border-color);
}
.file-list {
list-style: none;
display: grid;
gap: 10px;
}
.file-item {
display: flex;
align-items: center;
padding: 15px;
background: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: 6px;
text-decoration: none;
color: inherit;
transition: all 0.2s ease;
animation: fadeInUp 0.3s ease;
animation-fill-mode: both;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.file-item:hover {
background: var(--hover-bg);
transform: translateY(-2px);
border-color: var(--accent-color);
box-shadow: 0 4px 12px var(--shadow);
}
.file-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--file-icon);
border-radius: 4px;
margin-right: 15px;
font-size: 0.8rem;
font-weight: 600;
color: white;
text-transform: uppercase;
}
.file-icon.folder {
background: var(--folder-icon);
}
.file-info {
flex: 1;
overflow: hidden;
}
.file-name {
font-weight: 500;
color: var(--text-primary);
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.06rem;
}
.file-meta {
font-size: 0.875rem;
color: var(--text-secondary);
}
.empty-folder {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.back-link {
display: inline-block;
margin-bottom: 20px;
color: var(--accent-color);
text-decoration: none;
padding: 8px 16px;
background: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: 4px;
transition: all 0.2s;
font-size: 0.9rem;
}
.back-link:hover {
background: var(--hover-bg);
transform: translateX(-5px);
}
@media (max-width: 768px) {
.file-list {
grid-template-columns: 1fr;
}
h1 {
font-size: 1.5rem;
}
.header-top {
flex-direction: column;
gap: 15px;
align-items: flex-start;
}
}
</style>
<!-- External CSS for global search -->
<link rel="stylesheet" href="../../../../../../../css/global-search.css">
<!-- Shared navbar styles -->
<link rel="stylesheet" href="../../../../../../../css/navbar.css">
</head>
<body>
<!-- Navbar will be injected here -->
<div data-navbar-placeholder></div>
<div class="container">
<div class="content">
<div class="section">
<h2 class="section-title">Folders</h2>
<ul class="file-list">
<li>
<a href="./egypt/" class="file-item">
<div class="file-icon folder">DIR</div>
<div class="file-info">
<div class="file-name">egypt</div>
<div class="file-meta">26 items</div>
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
<!-- External JavaScript for global search -->
<script src="../../../../../../../js/global-search.js"></script>
<script>
// Theme toggle functionality
function toggleTheme() {
const html = document.documentElement;
const buttons = document.querySelectorAll('.theme-toggle-nav');
if (!html) return;
const currentTheme = html.getAttribute('data-theme');
if (currentTheme === 'dark') {
html.setAttribute('data-theme', 'light');
buttons.forEach(btn => btn.textContent = '🌓 Theme');
localStorage.setItem('theme', 'light');
} else {
html.setAttribute('data-theme', 'dark');
buttons.forEach(btn => btn.textContent = '☀️ Theme');
localStorage.setItem('theme', 'dark');
}
}
// Initialize theme on page load - DARK MODE IS DEFAULT
document.addEventListener('DOMContentLoaded', function() {
const savedTheme = localStorage.getItem('theme') || 'dark'; // Default to dark mode
const html = document.documentElement;
const buttons = document.querySelectorAll('.theme-toggle-nav');
if (html) {
html.setAttribute('data-theme', savedTheme);
buttons.forEach(btn => {
btn.textContent = savedTheme === 'dark' ? '☀️ Theme' : '🌓 Theme';
});
}
// Initialize global search
if (typeof initGlobalSearch === 'function') {
initGlobalSearch();
}
// Check for search parameter in URL
const urlParams = new URLSearchParams(window.location.search);
const searchTerm = urlParams.get('search');
if (searchTerm) {
const searchInput = document.getElementById('searchInput');
if (searchInput) {
searchInput.value = searchTerm;
// Enable entire site search by default when using URL parameter
if (!isEntireSiteSearch) {
toggleSearchScope();
}
performSearch(searchTerm);
}
}
});
// Quick Navigation Toggle
function toggleQuickNav() {
const dropdown = document.getElementById('quickNavDropdown');
if (dropdown) {
dropdown.classList.toggle('active');
}
}
// Close quick nav when clicking outside
document.addEventListener('click', function(e) {
const container = document.querySelector('.quick-nav-container');
const dropdown = document.getElementById('quickNavDropdown');
if (container && dropdown && !container.contains(e.target)) {
dropdown.classList.remove('active');
}
});
// Search functionality
let isEntireSiteSearch = false;
let searchIndex = null;
// Load search index for entire site search
async function loadSearchIndex() {
if (searchIndex) return searchIndex;
try {
const response = await fetch('/search_index.json');
if (response.ok) {
searchIndex = await response.json();
console.log('✅ Global search index loaded:', searchIndex.total_items, 'items');
return searchIndex;
}
} catch (error) {
console.log(' Using local folder search only');
}
return null;
}
function toggleSearchScope() {
isEntireSiteSearch = !isEntireSiteSearch;
const toggle = document.getElementById('scopeToggle');
const label = document.getElementById('scopeLabel');
const input = document.getElementById('searchInput');
if (toggle) {
toggle.classList.toggle('active', isEntireSiteSearch);
}
if (label) {
label.textContent = isEntireSiteSearch ? 'Entire Site' : 'Current Folder';
}
if (input) {
input.placeholder = isEntireSiteSearch ? 'Search entire site...' : 'Search in current folder...';
}
// Re-perform search if there's text
const currentValue = input ? input.value : '';
if (currentValue) {
performSearch(currentValue);
}
}
function handleSearch(event) {
if (event.key === 'Escape') {
clearSearch();
return;
}
const searchTerm = event.target.value.trim();
if (searchTerm.length > 0) {
performSearch(searchTerm);
} else {
clearSearch();
}
}
async function performSearch(searchTerm) {
const resultsDiv = document.getElementById('searchResults');
if (!resultsDiv) return;
if (isEntireSiteSearch) {
await performGlobalSearch(searchTerm, resultsDiv);
} else {
performLocalSearch(searchTerm, resultsDiv);
}
}
function performLocalSearch(searchTerm, resultsDiv) {
const term = searchTerm.toLowerCase();
const items = document.querySelectorAll('.file-item');
const results = [];
items.forEach(item => {
const nameElement = item.querySelector('.file-name');
if (nameElement) {
const name = nameElement.textContent.toLowerCase();
if (name.includes(term)) {
results.push({
element: item,
name: nameElement.textContent,
href: item.href,
type: item.querySelector('.file-icon').textContent,
meta: item.querySelector('.file-meta').textContent
});
}
}
});
displaySearchResults(results, searchTerm, resultsDiv, false);
}
async function performGlobalSearch(searchTerm, resultsDiv) {
const index = await loadSearchIndex();
if (!index) {
resultsDiv.innerHTML = '<div class="search-results-header"> Global search not available. Showing local results only.</div>';
resultsDiv.classList.add('active');
performLocalSearch(searchTerm, resultsDiv);
return;
}
const term = searchTerm.toLowerCase();
const matches = index.items.filter(item =>
item.name.toLowerCase().includes(term)
).slice(0, 50); // Limit to 50 results
displaySearchResults(matches, searchTerm, resultsDiv, true);
}
function displaySearchResults(results, searchTerm, resultsDiv, isGlobal) {
if (results.length === 0) {
resultsDiv.innerHTML = `
<div class="search-results-header">😕 No results found</div>
<p style="color: var(--text-secondary); padding: 10px;">Try different keywords or check your spelling.</p>
`;
resultsDiv.classList.add('active');
return;
}
const scopeText = isGlobal ? '🌐 Global Search' : '📁 Local Search';
let html = `<div class="search-results-header">${scopeText} Results (${results.length} found)</div>`;
results.forEach(result => {
const highlightedName = highlightMatch(result.name, searchTerm);
const icon = result.type === 'DIR' || result.type === 'Folder' ? '[DIR]' : '[FILE]';
html += `
<a href="${result.href || result.path}" class="search-result-item">
<div class="search-result-icon">${icon}</div>
<div class="search-result-info">
<div class="search-result-name">${highlightedName}</div>
<div class="search-result-meta">${result.type || 'File'}${result.meta || result.size || ''} ${result.location ? '• ' + result.location : ''}</div>
</div>
</a>
`;
});
resultsDiv.innerHTML = html;
resultsDiv.classList.add('active');
}
function highlightMatch(text, searchTerm) {
const escaped = escapeRegex(searchTerm);
const regex = new RegExp('(' + escaped + ')', 'gi');
return text.replace(regex, '<span class="highlight">$1</span>');
}
function escapeRegex(string) {
// Escape special regex characters
return string.split('').map(function(char) {
if ('[]/{}()*+?.-^$|\\'.indexOf(char) !== -1) {
return '\\' + char;
}
return char;
}).join('');
}
function clearSearch() {
const input = document.getElementById('searchInput');
const resultsDiv = document.getElementById('searchResults');
if (input) input.value = '';
if (resultsDiv) {
resultsDiv.classList.remove('active');
resultsDiv.innerHTML = '';
}
}
// ===== AUTO-REFRESH TO DETECT CHANGES (works on remote hosting) =====
(function() {
const REFRESH_INTERVAL = 30000; // 30 seconds
const STORAGE_KEY = 'last_index_update_' + window.location.pathname;
// Store initial load time
if (!sessionStorage.getItem(STORAGE_KEY)) {
sessionStorage.setItem(STORAGE_KEY, Date.now());
}
// Check for content changes periodically
setInterval(function() {
fetch(window.location.href, { cache: 'no-store' })
.then(response => response.text())
.then(html => {
const parser = new DOMParser();
const newDoc = parser.parseFromString(html, 'text/html');
const currentStats = document.querySelector('.stats');
const newStats = newDoc.querySelector('.stats');
// If stats changed (folder/file count), reload the page
if (currentStats && newStats && currentStats.innerHTML !== newStats.innerHTML) {
console.log('📄 Directory contents changed, refreshing...');
window.location.reload();
}
})
.catch(err => console.log('Checking for updates...'));
}, REFRESH_INTERVAL);
})();
</script>
<!-- Load shared navbar component -->
<script src="../../../../../../../js/navbar-loader.js"></script>
</body>
</html>