Update travel website submodule

This commit is contained in:
yourname
2026-07-03 18:01:32 +03:00
parent 59f1cf4a8b
commit e2960b802a
8 changed files with 1951 additions and 135 deletions

711
index.html Normal file
View File

@@ -0,0 +1,711 @@
<!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>