- Update website footer to improve responsiveness and layout. - Improve the styling and layout of the Home page components. - Update the Layout component to handle mobile sidebar better. - Improve Markdown rendering for better responsiveness. - Remove unused NavBar component. - Remove svelte-vscode extension from extensions.json. - Add .vscode folder to .gitignore to prevent accidental commits.
113 lines
4.1 KiB
Svelte
113 lines
4.1 KiB
Svelte
<script lang="ts">
|
|
import type { NavItem } from "../types/nav";
|
|
import { ChevronDown, X } from "lucide-svelte";
|
|
import { onMount } from "svelte";
|
|
|
|
export let navData: NavItem[] = [];
|
|
export let onNavItemClick: (path: string) => void = () => {};
|
|
export let visible: boolean = true;
|
|
export let isMobile: boolean = false;
|
|
|
|
// Track which sections are expanded
|
|
let expanded: Record<string, boolean> = {};
|
|
|
|
// Track active item
|
|
let activePath: string = "";
|
|
|
|
// Auto-expand the section containing the active item
|
|
$: if (activePath) {
|
|
// Find which section contains this path
|
|
navData.forEach((item) => {
|
|
if (item.children) {
|
|
const hasActivePath = item.children.some(
|
|
(child) => child.link === activePath,
|
|
);
|
|
if (hasActivePath) {
|
|
expanded[item.label] = true;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function toggleSection(label: string) {
|
|
expanded[label] = !expanded[label];
|
|
}
|
|
|
|
function handleNavItemClick(path: string, event: MouseEvent) {
|
|
event.preventDefault();
|
|
activePath = path;
|
|
|
|
// Convert URL path to document path
|
|
// Remove leading slash
|
|
const docPath = path.replace(/^\//, "");
|
|
|
|
// Call the event handler prop
|
|
onNavItemClick(docPath);
|
|
}
|
|
|
|
// Initialize with first section expanded
|
|
onMount(() => {
|
|
if (navData.length > 0) {
|
|
expanded[navData[0].label] = true;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<aside
|
|
class="sidebar bg-gray-50 border-r border-gray-200 h-screen fixed top-0 left-0 pt-16 overflow-y-auto shadow-sm z-20
|
|
{isMobile ? 'w-[85%] max-w-xs' : 'w-64'}
|
|
transition-transform duration-300 ease-in-out
|
|
{visible ? 'translate-x-0' : '-translate-x-full'}"
|
|
>
|
|
<nav class="w-full">
|
|
{#each navData as item}
|
|
{#if item.children && item.children.length > 0}
|
|
<div class="border-b border-gray-200">
|
|
<button
|
|
class="flex justify-between items-center w-full text-left p-3 sm:p-4 hover:bg-gray-100 text-gray-700 font-medium"
|
|
on:click={() => toggleSection(item.label)}
|
|
>
|
|
<span class="truncate">{item.label}</span>
|
|
<ChevronDown
|
|
class="h-4 w-4 flex-shrink-0 transition-transform duration-200 {expanded[
|
|
item.label
|
|
]
|
|
? 'rotate-180'
|
|
: ''}"
|
|
/>
|
|
</button>
|
|
|
|
{#if expanded[item.label]}
|
|
<div class="bg-gray-50">
|
|
{#each item.children as child}
|
|
<a
|
|
href={child.link}
|
|
class="block p-3 pl-6 sm:pl-8 hover:bg-gray-100 text-gray-600 border-t border-gray-100 truncate {activePath ===
|
|
child.link
|
|
? 'bg-blue-50 text-blue-700 font-medium'
|
|
: ''}"
|
|
on:click={(e) =>
|
|
handleNavItemClick(child.link, e)}
|
|
>
|
|
{child.label}
|
|
</a>
|
|
{/each}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
{:else}
|
|
<a
|
|
href={item.link}
|
|
class="block p-3 sm:p-4 hover:bg-gray-100 text-gray-700 border-b border-gray-200 truncate {activePath ===
|
|
item.link
|
|
? 'bg-blue-50 text-blue-700 font-medium'
|
|
: ''}"
|
|
on:click={(e) => handleNavItemClick(item.link, e)}
|
|
>
|
|
{item.label}
|
|
</a>
|
|
{/if}
|
|
{/each}
|
|
</nav>
|
|
</aside>
|